• IdentityServer用户名密码模式


    前言

    用户名密码模式相较于客户端凭证模式,多了用户。通过用户的用户名和密码向Identity Server申请访问令牌。密码模式有两种实现方式.
    1.把用户写进内存Identity从中读取账号密码验证
    AddInMemoryUsers(config.GetUsers())

    2.通过实现 IResourceOwnerPasswordValidator 接口来验证用户
    AddResourceOwnerValidator(ResourcePasswordValidator)

    第二种更加实用灵活,这篇笔记也是实现的第二种。

    20191223142903.png

    实现用户名密码授权

    我们在之前的搭建好的Identity服务上新增一个名为 ResourcePasswordValidator 的类继承 IResourceOwnerPasswordValidator 重写ValidateAsync 方法来验证用户名和密码

    using System.Security.Claims;
    using System.Threading.Tasks;
    using IdentityModel;
    using IdentityServer4.Models;
    using IdentityServer4.Validation;
    
    namespace IdentityServer
    {
        public class ResourcePasswordValidator: IResourceOwnerPasswordValidator
        {
            public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
            {
                //判断账号密码是否正确。
                if (context.UserName == "userName" && context.Password == "1234567")
                {
                    context.Result = new GrantValidationResult(
                     subject: "userInfo",
                        authenticationMethod: OidcConstants.AuthenticationMethods.Password,
                        claims: GetUserClaims());
                }
                else
                {
                    //验证失败
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
                }
            }
    
            //可以根据需要设置相应的Claim/需要实现IProfileService接口
            private Claim[] GetUserClaims()
            {
    
                return new Claim[]
                {
                new Claim("userId","110"),
                new Claim(JwtClaimTypes.Name,"林辉"),
                new Claim(JwtClaimTypes.Role,"菜鸡")
                };
            }
        }
    }
    

    Config.cs 中新增一个客户端

    new Client
    {
        ClientId = "client_b",
        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
        //AccessToken过期时间(秒),默认为3600秒/1小时
        AccessTokenLifetime=3600,
    
        //RefreshToken的最长生命周期
        //AbsoluteRefreshTokenLifetime = 2592000,
    
        //RefreshToken生命周期以秒为单位。默认为1296000秒
        SlidingRefreshTokenLifetime = 2592000,//以秒为单位滑动刷新令牌的生命周期。
    
        //刷新令牌时,将刷新RefreshToken的生命周期。RefreshToken的总生命周期不会超过AbsoluteRefreshTokenLifetime。
        RefreshTokenExpiration = TokenExpiration.Sliding,
    
        //AllowOfflineAccess 允许使用刷新令牌的方式来获取新的令牌
        AllowOfflineAccess = true,
        ClientSecrets =
        {
            new Secret("secret".Sha256())
        },
        AllowedScopes = { "Api"}
    }
    

    新建一个 ProfileService 来实现 IProfileService 接口来扩展自定义Claim

    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using IdentityServer4.Models;
    using IdentityServer4.Services;
    
    namespace IdentityServer
    {
        public class ProfileService : IProfileService
        {
            public async Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                try
                {
                    //depending on the scope accessing the user data.
                    var claims = context.Subject.Claims.ToList();
    
                    //set issued claims to return
                    context.IssuedClaims = claims.ToList();
                }
                catch (Exception ex)
                {
                    //log your error
                }
            }
    
            public async Task IsActiveAsync(IsActiveContext context)
            {
                context.IsActive = true;
            }
        }
    }
    

    
    修改 Startup

    //注入DI
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResourceResources())
        .AddInMemoryApiResources(Config.GetApiResources())//Api资源信息
        .AddInMemoryClients(Config.GetClients())//客户端信息
        .AddResourceOwnerValidator<ResourcePasswordValidator>()//用户验证
        .AddProfileService<ProfileService>();//扩展claims
    

    测试效果

    通过用户名密码申请令牌

    20191223155822.png

    当access_token过期的时候通过refresh_token来刷新access_token,refresh_token只能使用一次,每次刷新后会返给信的refresh_token和access_token

    20191223172456.png

    我们通过jwt.io解析出来。可以发现jwt里面包含了我们添加的身份信息,这些信息可以直接在资源服务器中获取使用

    20191223160011.png

    修改资源服务器

    我们在Api中可以通过 User.Claims.FirstOrDefault(m => m.Type == "userId").value; 获取我们用户身份信息。

    [HttpGet("userInfo")]
    [Authorize]
    public ActionResult UserIno()
    {
        return new JsonResult($"用户id{User.Claims.FirstOrDefault(m => m.Type == "userId").Value }" );
    }
    

    20191223160044.png

  • 相关阅读:
    九月读书笔记
    Apache Shiro 使用手册(一)Shiro架构介绍
    通过js动态生成页面表格
    PHP 命名空间与自动加载机制介绍
    PHP PSR 代码规范基本介绍
    PHP 图像居中裁剪函数
    PHP 获取IP地址位置信息「聚合数据API」
    HTML5 图片本地压缩上传插件「localResizeIMG」
    Apache 配置多站点访问「为项目分配二级域名」
    PHP 文件夹操作「复制、删除、查看大小」迭代实现
  • 原文地址:https://www.cnblogs.com/linhuiy/p/12084940.html
Copyright © 2020-2023  润新知