1. 程式人生 > >IdentityServer4(8)- 使用密碼認證方式控制API訪問(資源所有者密碼授權模式)

IdentityServer4(8)- 使用密碼認證方式控制API訪問(資源所有者密碼授權模式)

原文: IdentityServer4(8)- 使用密碼認證方式控制API訪問(資源所有者密碼授權模式)

一.前言

本文及IdentityServer這個系列使用的都是基於.net core 2.0的。上一篇博文在API專案中我使用了Microsoft.AspNetCore.Authentication.JwtBearer元件來代替IdentityServer4.AccessTokenValidation元件,今天(2017-9-12)我發現後者已經更新到了2.0.0,支援.net core 2.0,所以現在所使用的元件已經更新為後者,在程式碼裡我有詳細註釋。

二.資源所有者密碼授權模式(ResourceOwnerPassword)

OAuth 2.0 資源所有者密碼模式授權允許一個客戶端傳送使用者名稱和密碼到IdentityServer並獲得一個表示該使用者的可以用於訪問api的Token。

該規範建議僅對“受信任”應用程式使用資源所有者密碼授權。 一般來說,當您要驗證使用者並請求訪問令牌時,通常使用互動式OpenID Connect流會更好。

不過,這個授權型別允許我們在 IdentityServer 快速入門中引入 使用者 的概念,這是我們要展示它的原因。

三.新增使用者

就像基於記憶體儲存的資源(即 Scopes)和客戶端一樣,對於使用者也可以這樣做。

注意:檢視基於 ASP.NET Identity 的快速入門以獲得更多關於如何正確儲存和管理使用者賬戶的資訊。

TestUser型別表示一個測試使用者及其身份資訊。讓我們向配置類(如果你有嚴格按照順序進行演練,那麼配置類應該在 QuickstartIdentityServer 專案的 Config.cs 檔案中)中新增以下程式碼以建立一對使用者:

首先新增以下語句 到Config.cs檔案中:

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password"
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password"
        }
    };
}

然後將測試使用者註冊到 IdentityServer:

public void ConfigureServices(IServiceCollection services)
{
    // 使用記憶體儲存,金鑰,客戶端和資源來配置身份伺服器。
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())//新增api資源
        .AddInMemoryClients(Config.GetClients())//新增客戶端
        .AddTestUsers(Config.GetUsers()); //新增測試使用者
}

AddTestUsers 方法幫我們做了以下幾件事:

  • 為資源所有者密碼授權新增支援
  • 新增對使用者相關服務的支援,這服務通常為登入 UI 所使用(我們將在下一個快速入門中用到登入 UI)
  • 為基於測試使用者的身份資訊服務新增支援(你將在下一個快速入門中學習更多與之相關的東西)

四.為資源所有者密碼授權新增一個客戶端定義

你可以通過修改 ·AllowedGrantTypes· 屬性簡單地新增對已有客戶端授權型別的支援。

通常你會想要為資源所有者用例建立獨立的客戶端,新增以下程式碼到你配置中的客戶端定義中:

// client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "client",
            // 沒有互動性使用者,使用 clientid/secret 實現認證。
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // 用於認證的密碼
            ClientSecrets = 
            {
                new Secret("secret".Sha256())
            },
            // 客戶端有權訪問的範圍(Scopes)
            AllowedScopes = { "api1" }
        },
        // resource owner password grant client
        new Client
        {
            ClientId = "ro.client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            AllowedScopes = { "api1" }
        }
    };
}

使用密碼授權請求一個令牌
客戶端看起來跟之前客戶端證書授權的客戶端是相似的。主要差別在於現在的客戶端將會以某種方式收集使用者密碼,然後在令牌請求期間傳送到令牌服務。

IdentityModel 的 TokenClient 在這裡再次為我們提了供幫助:

// 從元資料中發現客戶端
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");

// 請求令牌
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");//使用使用者名稱密碼

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

當你傳送令牌到身份 API 端點的時候,你會發現與客戶端憑證授權
相比,資源所有者密碼授權有一個很小但很重要的區別。訪問令牌現在將包含一個 sub 資訊,該資訊是使用者的唯一標識。sub 資訊可以在呼叫 API 後通過檢查內容變數來被檢視,並且也將被控制檯應用程式顯示到螢幕上。

sub 資訊的存在(或缺失)使得 API 能夠區分代表客戶端的呼叫和代表使用者的呼叫。

sub

下面這張圖,是理解的客戶端請求流程,

關於上圖的補充說明,這裡講一下。api資源收到第一個請求之後,會去id4伺服器公鑰,然後用公鑰驗證token是否合法,如果合法進行後面後面的有效性驗證。有且只有第一個請求才會去id4伺服器請求公鑰,後面的請求都會用第一次請求的公鑰來驗證,這也是jwt去中心化驗證的思想。

五.使用Postman除錯

使用postman呼叫生成token介面需要配置如下引數:

最後github地址:https://github.com/stulzq/IdentityServer4.Samples/tree/master/Quickstarts/2_ResourceOwnerPasswords 如果你覺得對你有用,歡迎star