文章出處

之前寫了一篇文章:《IdentityServer4 實現 OpenID Connect 和 OAuth 2.0

上面這篇文章雖然詳細,但都是點到為止的介紹,并沒有實際應用的示例,所以,后面在真正去實現的時候,踩到了自己之前種下的很多坑。

業務場景:前后端分離項目,前端調用后端業務服務需要授權訪問(提供access_token),access_token在用戶登錄的時候(用戶名和密碼登錄),由授權中心生成access_token并返回給前端,這樣前端就可以拿到access_token,去調用后端業務服務了。

一開始,我使用的GrantTypes.Implicit模式,登錄頁面在授權中心,登錄成功之后會跳到callback.htm#access_token=*頁面,前端調用使用oidc-client組件,然后獲取access_token,當時使用還沒什么,現在覺得真是一團亂麻,前后端分離的項目,在授權中心居然把登錄頁面放在服務中了,但我后面還是沒有意識到GrantTypes.Implicit的問題,而是嘗試在這種模式下,寫HTTP Post請求授權中心(提供用戶名和密碼),然后沒然后,一團糟。。。

使用 IdentityServer4 實現上面的業務場景,其實很簡單,只要使用GrantTypes.GrantTypes.ResourceOwnerPassword模式,就可以了。

Startup.ConfigureServices配置代碼:

var builder = services.AddIdentityServer();
builder.AddTemporarySigningCredential()
        //.AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(new List<Client>
        {
            new Client
            {
                ClientId = "client_id_1",
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                AllowOfflineAccess = true,
                AccessTokenLifetime = 3600 * 6, //6小時
                SlidingRefreshTokenLifetime = 1296000, //15天
                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OfflineAccess, 
                    "api1"
                }
            }});
builder.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();

ResourceOwnerPasswordValidator示例代碼:

public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    private readonly IUserService _userService;

    public ResourceOwnerPasswordValidator(IUserService userService)
    {
        _userService = userService;
    }

    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        var userId = await _userService.Login(context.UserName, context.Password);
        if (userId != 0)
        {
            context.Result = new GrantValidationResult(userId.ToString(), OidcConstants.AuthenticationMethods.Password);
        }
    }
}

使用ResourceOwnerPasswordValidator的作用,就是自定義用戶登錄的用戶名密碼判斷,而不是使用 IdentityServer4 的TestUser

請求示例:IdentityServer4 Token Endpoint

獲取access_token請求示例:

刷新access_token請求示例:

也可以服務端進行請求,示例代碼:

private async Task<TokenResponse> GetToken(string clientId, string clientSecret, string grantType, string userName, string password, string scope)
{
    var client = new DiscoveryClient($"http://localhost:5001");
    client.Policy.RequireHttps = false;
    var disco = await client.GetAsync();
    var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
    return await tokenClient.RequestResourceOwnerPasswordAsync(userName, password, scope);
}

private async Task<TokenResponse> GetRefreshToken(string clientId, string clientSecret, string grantType, string refreshToken)
{
    var client = new DiscoveryClient($"http://localhost:5001");
    client.Policy.RequireHttps = false;
    var disco = await client.GetAsync();
    var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
    return await tokenClient.RequestRefreshTokenAsync(refreshToken);
}

參考資料:


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()