[鉴权/授权].Net6下Jwt与RefreshToken的结合

微信公众号:趣编程ACE
关注可了解.NET日常开发技巧。如需源码,请公众号留言 源码;

上文回顾

【鉴权/授权】一步一步实现一个简易JWT鉴权

【鉴权/授权】自定义一个身份认证Handler

【鉴权/授权】基于角色的简单授权认证

如何基于JWT实现RefreshToken

在前面的几篇文章中,我一点一点分享了如何利用JWT鉴权、自定义鉴权、基于角色的授权等知识点,如果想了解的请参阅上文回顾
今天这篇文章将分享如何在.net6项目下生成并利用refreshToken进行身份鉴权,亲测可用。。。。素来围观。。。。

创建RefreshToken

1    /// <summary>
 2    /// 生成refreshToken的接口
 3    /// </summary>
 4    public interface IGenerateRefreshToken
 5    {
 6        string GenerateRefreshTokenStr();
 7    }
 8
 9    /// <summary>
10    /// 生成RefreshToken的接口实例 
11    /// </summary>
12    public class GenerateRefreshTokenImpl: IGenerateRefreshToken
13    {
14        /// <summary>
15        /// 生成32位随机字符的refreshToken
16        /// </summary>
17        /// <returns></returns>
18        public string GenerateRefreshTokenStr()
19        {
20            var refreshBytes = new byte[32];
21            using (var number = RandomNumberGenerator.Create())
22            {
23                number.GetBytes(refreshBytes);
24                return Convert.ToBase64String(refreshBytes);
25            }
26        }
27    }


上面就是一个32位随机字符的refreshToken的接口及其实现方法,有了这个接口服务之后,我们需要在内置的依赖容器里面注入这个服务,于是来到Program.cs文件里面

1// 注入生成refreshToken的服务
2builder.Services.AddSingleton<IGenerateRefreshToken, GenerateRefreshTokenImpl>();

接着我们在登录的逻辑里面除了要生成Token同时也要调用我们上方的refreshToken接口来生成RefreshToken,生成成功后将TokenRefreshToken包裹成一个实体--ResponseModel一并返回给客户端,于是我们来到AuthenticateImpl这个类里面的Login方法。

1            // 生成RefreshToken  其中_generateRefreshToken 是从构造函数中依赖注入进来
2            var refreshToken = _generateRefreshToken.GenerateRefreshTokenStr();
3            // 将refreshToken 缓存起来 这一步可以存到数据库,也可以采用分布式缓存来替代,后续再分享
4            RefreshTokens[userName] = refreshToken;

其中RefreshTokens这个字典类型是这样产生的

1public interface IAuthenticate
2{
3        ResponseModel Login(string userName,string password); // 登录方法
4        Dictionary<string, string> RefreshTokens { get; set; } // refreshToken 缓存
5        ResponseModel Refresh(string userName, RefreshDto refreshDto);  // token失效后刷新方法
6}

然后AuthenticateImpl.cs方法实现这个属性。

Token失效后的Refresh方法(核心逻辑)

1[AllowAnonymous]
2[HttpPost("refresh")]
3public IActionResult Refresh(string userName ,RefreshDto refreshDto)
4{
5   return Ok(_authenticate.Refresh(userName, refreshDto));
6}

创建一个控制器,并书写一个Refresh的刷新方法,当我们前端发现Token失效的时候,我们将会携带失效的JWT以及之前登录时产生的RefreshToken来重新生成一个Token和RefreshToken ,以此来减轻对数据库查询压力。。。
那么这个Refresh方法的逻辑是什么呢?

1/// <summary>
 2/// 刷新验证 生成接口服务
 3/// </summary>
 4public interface IRefreshManager
 5{
 6        ResponseModel Refresh(RefreshDto refreshDto, Dictionary<string, string> dic, Claim[] claims);
 7}
 8/// <summary>
 9/// 刷新验证 生成接口实现
10/// </summary>
11public class RefreshManagerImpl:IRefreshManager
12    {
13        private readonly string _key;
14        private readonly IGenerateRefreshToken _generateRefreshToken;
15
16        public RefreshManagerImpl(string key, IGenerateRefreshToken generateRefreshToken)
17        {
18            this._key = key;
19            this._generateRefreshToken = generateRefreshToken;
20        }
21
22        public ResponseModel Refresh(RefreshDto refreshDto,Dictionary<string,string> dic,Claim[] claims)
23        {
24            var tokenHandler = new JwtSecurityTokenHandler();
25            SecurityToken validatedToken;
26            // 根据过期token获取一个 SecurityToken 
27            var principal =tokenHandler.ValidateToken(refreshDto.JwtToken, new TokenValidationParameters()
28            {
29                ValidateIssuerSigningKey = true,
30                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_key)),
31                ValidateIssuer = false,
32                ValidateAudience = false,
33                ValidateLifetime = false, // 不对tojen过期进行验证
34            }, out validatedToken);
35            var jwtToken = validatedToken as JwtSecurityToken;
36            // 算法验证
37            if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,StringComparison.InvariantCultureIgnoreCase))
38            {
39                throw new SecurityTokenException("token 不合法");
40            }
41            // 判读refreshToken是否是此用户生成的
42            var userName = principal.Identity.Name;
43            if(refreshDto.RefreshToken!=dic[userName] && refreshDto.RefreshToken==null)
44            {
45                throw new SecurityTokenException("refreshToken 不合法");
46            }
47
48            // 生成新token
49            var jwtSecurityToken = new JwtSecurityToken(
50                claims: claims, // 需要一个Claims对象  需要根据用户信息自定义生成生成
51                expires: DateTime.UtcNow.AddSeconds(60),
52                signingCredentials: new SigningCredentials(
53                    new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_key)),
54                    SecurityAlgorithms.HmacSha256Signature)
55                );
56
57            // 生成新token 和 refreshToken
58            var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
59            var refreshToken = _generateRefreshToken.GenerateRefreshTokenStr();
60            // 返回结果
61            return new ResponseModel() { JwtToken = token, RefreshToken = refreshToken };
62        }
63
64
65    }

上述就是Refresh方法的核心逻辑(详情见注释),我们将这个接口服务注入到容器中,以供控制器Api接口调用

1builder.Services.AddSingleton<IRefreshManager>(x => new RefreshManagerImpl(key, x.GetService<IGenerateRefreshToken>()));

调用此服务 由IAuthenticate.cs里面的方法调用

1public ResponseModel Refresh(string userName,RefreshDto refreshDto)
2        {
3            var claims = new Claim[] { new Claim(ClaimTypes.Name, userName) };
4            var tokenModel = _refreshManager.Refresh(refreshDto, RefreshTokens, claims);
5            RefreshTokens[userName] = tokenModel.RefreshToken;
6            return tokenModel;
7        }

以上便是JWT 生成RefreshToken的方法的大概逻辑,加上前面写的几篇文章,身份鉴权授权就暂分享这么多,后面再补充,最后感谢趣编程ACE公众号以及其他帮我分享文章的平台,Thanks~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值