入門教程:.NET開源OpenID Connect 和OAuth解決方案IdentityServer v3 建立簡單的OAuth2.0服務器,客戶端和API(三)

本教程的目的在於創造儘量簡單的identityserver安裝做爲一個oauth2受權服務器。這應該可以讓你瞭解一些基本功能和配置選項(完整的源代碼能夠發現在這裏)。在後面的文檔中會介紹更多的高級功能。本教程包括:git

  • 建立一個自託管identityservergithub

  • 設置爲使用一個應用程序的賬戶以及用戶對通訊應用的客戶服務表明web

  • 註冊一個APIapi

  • 請求訪問令牌瀏覽器

  • 調用API服務器

  • 驗證一個訪問令牌app

建立一個受權服務器(IdentityServer3)

建立一個控制檯應用程序,而且在程序包管理器控制檯中輸入ide

install-package identityserver3

註冊API

API做爲請求範圍,您須要註冊全部您但願可以請求訪問令牌的全部API,而後咱們建立一個類用於返回在這個做用範圍內全部的API測試

using IdentityServer3.Core.Models;

static class Scopes
{
    public static List<Scope> Get()
    {
        return new List<Scope>
        {
            new Scope
            {
                Name = "api1"
            }
        };
    }
}

註冊客戶端

如今咱們要註冊一個客戶端。這個客戶將可以申請api1 scope的資源。對於咱們的第一次迭代,將有沒有人蔘與,客戶端將簡單地要求表明本身的令牌(認爲機器與機器通訊)。ui

對於這個客戶端,咱們配置如下的東西:

  • 顯示名稱和編號(惟一的名稱)

  • 客戶端密鑰

  • 客戶端憑據 

  • 使用所謂的引用標記。參考標記不須要簽名證書。

  • 容許訪問的做用域("api1")

using IdentityServer3.Core.Models;

static class Clients
{
    public static List<Client> Get()
    {
        return new List<Client>
        {
           // no human involved
            new Client
            {
                ClientName = "Silicon-only Client",
                ClientId = "silicon",
                Enabled = true,
                AccessTokenType = AccessTokenType.Reference,

                Flow = Flows.ClientCredentials,

                ClientSecrets = new List<Secret>
                {
                    new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
                },

                AllowedScopes = new List<string>
                {
                    "api1"
                }
            }
        };
    }
}

 

配置 IdentityServer

identityserver做爲OWIN的中間件的實現,它是經過UseIdentityServer擴展方法在Startup類中配置。

下面的代碼配置一個使用咱們以前定義的客戶端個做用域的受權服務器,稍後咱們會添加用戶進來。

using Owin;
using System.Collections.Generic;
using IdentityServer3.Core.Configuration;
using IdentityServer3.Core.Services.InMemory;

namespace IdSrv
{
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var options = new IdentityServerOptions
            {
                Factory = new IdentityServerServiceFactory()
                            .UseInMemoryClients(Clients.Get())
                            .UseInMemoryScopes(Scopes.Get())
                            .UseInMemoryUsers(new List<InMemoryUser>()),
                            
                RequireSsl = false
            };

            app.UseIdentityServer(options);
        }
    }
}

 

添加日誌記錄

由於咱們在一個控制檯中運行,它是很是方便的日誌輸出直接到控制檯窗口。Serilog是一個很好的日誌庫

install-package serilog
install-package serilog.sinks.literate

 

託管 IdentityServer

最後一步是託管identityserver。在程序包管理控制檯添加OWIN

install-package Microsoft.Owin.SelfHost

 

在Program.cs文件中添加一下代碼:

// logging
Log.Logger = new LoggerConfiguration()
    .WriteTo
    .LiterateConsole(outputTemplate: "{Timestamp:HH:MM} [{Level}] ({Name:l}){NewLine} {Message}{NewLine}{Exception}")
    .CreateLogger();

// hosting identityserver
using (WebApp.Start<Startup>("http://localhost:5000"))
{
    Console.WriteLine("server running...");
    Console.ReadLine();
}

 

而後當你啓動控制檯程序的時候你會看到控制檯輸出「server running...」

 

添加一個 API

在這一部分中咱們將添加一個簡單的Web API,咱們只須要從identityserver設置一個訪問令牌。

建立API應用程序

在的解決方案中添加一個新的ASP.NET Web API 應用程序,選擇空模板

添加必要的NuGet包:

install-package Microsoft.Owin.Host.SystemWeb
install-package Microsoft.AspNet.WebApi.Owin
install-package IdentityServer3.AccessTokenValidation

添加Controller

添加這個簡單的測試控制器:

[Route("test")]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        var caller = User as ClaimsPrincipal;

        return Json(new
        {
            message = "OK computer",
            client =  caller.FindFirst("client_id").Value
        });
    }
}

 

控制器上的用戶屬性讓您從訪問令牌中訪問該請求的權限。

添加Startup

添加如下Startup.cs爲創建Web API和identityserver配置信任啓動類

using IdentityServer3.AccessTokenValidation;

public void Configuration(IAppBuilder app)
{
    // accept access tokens from identityserver and require a scope of 'api1'
    app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
        {
            Authority = "http://localhost:5000",
            ValidationMode = ValidationMode.ValidationEndpoint,

            RequiredScopes = new[] { "api1" }
        });

    // configure web api
    var config = new HttpConfiguration();
    config.MapHttpAttributeRoutes();

    // require authentication for all controllers
    config.Filters.Add(new AuthorizeAttribute());

    app.UseWebApi(config);
}

 

試着打開瀏覽器,訪問測試控制器-你應該看到一個401,由於必要的訪問令牌丟失。

添加Console客戶端

在下一部分中,咱們將添加一個簡單的控制檯客戶端,該客戶端將請求訪問令牌,並使用該接口進行身份驗證。

首先添加一個新的控制檯項目並安裝一oauth2客戶端須要的NuGet包:

install-package IdentityModel

 

第一段代碼 獲取客戶端Token使用客戶端證書:

using IdentityModel.Client;

static TokenResponse GetClientToken()
{
    var client = new TokenClient(
        "http://localhost:5000/connect/token",
        "silicon",
        "F621F470-9731-4A25-80EF-67A6F7C5F4B8");

    return client.RequestClientCredentialsAsync("api1").Result;
}

 

第二段代碼 使用訪問令牌調用API:

static void CallApi(TokenResponse response)
{
    var client = new HttpClient();
    client.SetBearerToken(response.AccessToken);

    Console.WriteLine(client.GetStringAsync("http://localhost:14869/test").Result);
}

若是你啓動控制檯程序,你應該看到{"message":"OK computer","client":"silicon"}在您的控制檯。

添加一個用戶

到目前爲止,客戶端請求一個訪問令牌自己,沒有用戶參與。讓咱們介紹一我的。

添加一個獲取用戶的服務

用戶服務管理用戶-對於這個示例,咱們將使用簡單的內存用戶服務。首先咱們須要定義一些用戶:

using IdentityServer3.Core.Services.InMemory;

static class Users
{
    public static List<InMemoryUser> Get()
    {
        return new List<InMemoryUser>
        {
            new InMemoryUser
            {
                Username = "bob",
                Password = "secret",
                Subject = "1"
            },
            new InMemoryUser
            {
                Username = "alice",
                Password = "secret",
                Subject = "2"
            }
        };
    }
}

 

用戶名和密碼被用來驗證用戶,subject是該用戶將被嵌入到訪問令牌的惟一標識符。使用Users.Get()替換Startup.cs中的new List<InMemoryUser>()

添加一個客戶端

接下來,咱們將添加一個客戶定義,使用流稱爲資源全部者的密碼證書授予。此流程容許客戶端將用戶的用戶名和密碼發送到令牌服務,並在返回中獲取訪問令牌。

using IdentityServer3.Core.Models;
using System.Collections.Generic;

namespace IdSrv
{
    static class Clients
    {
        public static List<Client> Get()
        {
            return new List<Client>
            {
                // no human involved
                new Client
                {
                    ClientName = "Silicon-only Client",
                    ClientId = "silicon",
                    Enabled = true,
                    AccessTokenType = AccessTokenType.Reference,

                    Flow = Flows.ClientCredentials,

                    ClientSecrets = new List<Secret>
                    {
                        new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
                    },

                    AllowedScopes = new List<string>
                    {
                        "api1"
                    }
                },

                // human is involved
                new Client
                {
                    ClientName = "Silicon on behalf of Carbon Client",
                    ClientId = "carbon",
                    Enabled = true,
                    AccessTokenType = AccessTokenType.Reference,

                    Flow = Flows.ResourceOwner,

                    ClientSecrets = new List<Secret>
                    {
                        new Secret("21B5F798-BE55-42BC-8AA8-0025B903DC3B".Sha256())
                    },

                    AllowedScopes = new List<string>
                    {
                        "api1"
                    }
                }
            };
        }
    }
}

 

更新API

當涉及到人的時候,訪問令牌將包含子請求以惟一標識用戶。讓咱們對API的控制器作小的修改,:

[Route("test")]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        var caller = User as ClaimsPrincipal;

        var subjectClaim = caller.FindFirst("sub");
        if (subjectClaim != null)
        {
            return Json(new
            {
                message = "OK user",
                client = caller.FindFirst("client_id").Value,
                subject = subjectClaim.Value
            });
        }
        else
        {
            return Json(new
            {
                message = "OK computer",
                client = caller.FindFirst("client_id").Value
            });
        }
    }
}

 

更新客戶端

下一個向客戶端添加一個新的方法,表明用戶請求訪問令牌:

static TokenResponse GetUserToken()
{
    var client = new TokenClient(
        "http://localhost:5000/connect/token",
        "carbon",
        "21B5F798-BE55-42BC-8AA8-0025B903DC3B");

    return client.RequestResourceOwnerPasswordAsync("bob", "secret", "api1").Result;
}

如今再次嘗試獲取token看看API返回的信息吧

相關文章
相關標籤/搜索