zoukankan      html  css  js  c++  java
  • IdentityServer4 实现 OAuth 2.0(密码模式

    之前写了一篇文章:《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);
    }
    

    参考资料:

  • 相关阅读:
    MyBatis 智能标签
    MyBatis入门
    Hibernate 分组查询 子查询 原生SQL
    组件映射
    Hibernate组件映射
    hibernate 中的 lazy=”proxy” 和 lazy=”no-proxy” 的区别
    save(),saveOrUpdate(),merge()的区别
    ThreadLocal
    OID,主键生成策略,PO VO DTO,get和load区别,脏检查,快照,java对象的三种状态
    HIbernate实现增、删、改、查。
  • 原文地址:https://www.cnblogs.com/xishuai/p/identityserver4-ResourceOwnerPassword-GrantType-and-http-post.html
Copyright © 2011-2022 走看看