ASP.NET Core生成,校验jwt的(accessToken)访问令牌和(refreshToken)刷新令牌示例讲解

ASP.NET Core生成,校验jwt的(accessToken)访问令牌和(refreshToken)刷新令牌示例讲解

-懒狗如我,解析都写到注释里了,写的很详细,不懂的地方翻翻文档

微软文档

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using jwt.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace jwtTest.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class SignInController : Controller
    {
        private IConfiguration _configuration { get; set; }

        // 控制器注入Configuration依赖,方便获取appsettinfs.json中的SecurityKey
        public SignInController(IConfiguration config)
        {
            _configuration = config;
        }


        [HttpGet("login")]
        public ActionResult Login(string username, string password)//应该写个LoginDto,我懒了
        {
            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();

                //在此进行账号密码认证,此代码省略

                //------------生成AccessToken----------------------------------
                // token中的claims用于储存自定义信息,如登录之后的用户id等
                var claims = new[]
                {
                    new Claim("username",username),
                    new Claim("password",password),//演示用,(不要把密码写进token啊喂!!!(#`O′))
                    //new Claim(ClaimTypes.Role,"admin")
                    new Claim("role","admin")//此写法和上面写法效果一样
                };
                // 获取SecurityKey
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"));
                //生成Token
                var token = new JwtSecurityToken(
                    issuer: "cxy",                    // 发布者
                    audience: "myClient",                // 接收者
                    notBefore: DateTime.Now,                                                          // token签发时间
                    expires: DateTime.Now.AddMinutes(30),                                             // token过期时间
                    claims: claims,                                                                   // 该token内存储的自定义字段信息
                    signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)    // 用于签发token的秘钥算法
                );
                //-----------下面是生成RefreshToken--------------------------
                var refClaims = new[]
               {
                    new Claim("role","refresh")
                };
                var refreshToken = new JwtSecurityToken(
                    issuer: "cxy",                    // 发布者
                    audience: "myClient",                // 接收者
                    notBefore: DateTime.Now,                                                          // token签发时间
                    expires: DateTime.Now.AddDays(7),                                             // token过期时间
                    claims: refClaims,                                                                   // 该token内存储的自定义字段信息
                    signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)    // 用于签发token的秘钥算法
                );

                // 返回成功信息,写出token
                return Ok(new { code = 200, message = "登录成功", accessToken = jwtSecurityTokenHandler.WriteToken(token), refreshToken = jwtSecurityTokenHandler.WriteToken(refreshToken) });
            }
            // 返回错误请求信息
            return BadRequest(new { code = 400, message = "登录失败,用户名或密码为空" });
        }







        //此方法用来刷新令牌,逻辑是验证refToken才能进入方法,进入后验证accessToken除了过期时间项的其他所有项,目的是防止用户修改权限等
        [HttpPost("refresh")]
        [Authorize(Roles = "refresh")]//验证权限
        public ActionResult Refresh(RefreshDto refreshDto)
        {
            var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();//这个类是老朋友了

            bool isCan =jwtSecurityTokenHandler.CanReadToken(refreshDto.AccessToken);//验证Token格式
            if (!isCan)
                return BadRequest(new { code = 400, message = "传入访问令牌格式错误" });
            //var jwtToken = jwtSecurityTokenHandler.ReadJwtToken(refreshDto.AccessToken);//转换类型为token,不用这一行


           
            
            var validateParameter = new TokenValidationParameters()//验证参数
            {
                ValidateAudience = true,
                // 验证发布者
                ValidateIssuer = true,
                // 验证过期时间
                ValidateLifetime = false,
                // 验证秘钥
                ValidateIssuerSigningKey = true,
                // 读配置Issure
                ValidIssuer = "cxy",
                // 读配置Audience
                ValidAudience = "myClient",
                // 设置生成token的秘钥
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"))
            };

            //验证传入的过期的AccessToken
            SecurityToken validatedToken = null;
            try
            {
                jwtSecurityTokenHandler.ValidateToken(refreshDto.AccessToken, validateParameter,out validatedToken);//微软提供的验证方法。那个out传出的参数,类型是是个抽象类,记得转换
            }
            catch(SecurityTokenException)
            {
                return BadRequest(new {code=400, message= "传入AccessToken被修改" });
            }
           



            // 获取SecurityKey
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"));//不要学我写这里啊,我是懒狗,写appsettings.json这里去,写到类的属性里,注入一下

            var refClaims = new[]
                {
                    new Claim("role","refresh")
                };
            var refreshToken = new JwtSecurityToken(
                issuer: "cxy",                    // 发布者
                audience: "myClient",                // 接收者
                notBefore: DateTime.Now,                                                          // token签发时间
                expires: DateTime.Now.AddDays(7),                                             // token过期时间
                claims: refClaims,                                                                   // 该token内存储的自定义字段信息
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)    // 用于签发token的秘钥算法
            );

            var jwtToken = validatedToken as JwtSecurityToken;//转换一下
            var accClaims = jwtToken.Claims;
            var accessToken = new JwtSecurityToken(
                    issuer: "cxy",                    // 发布者
                    //audience: "myClient",                // 接收者
                    notBefore: DateTime.Now,                                                          // token签发时间
                    expires: DateTime.Now.AddMinutes(30),                                             // token过期时间
                    claims: accClaims,                                                                   // 该token内存储的自定义字段信息
                    signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)    // 用于签发token的秘钥算法
                );


            // 返回成功信息,写出token
            return Ok(new {
                code = 200, message = "令牌刷新成功", refreshToken =jwtSecurityTokenHandler.WriteToken(refreshToken), accessToken =new JwtSecurityTokenHandler().WriteToken(accessToken)
            });
        }
    }
}
posted @ 2021-08-08 19:10  原上草_0000  阅读(1259)  评论(1编辑  收藏  举报