.NET 6 JWT验证

发布时间 2023-08-24 21:23:11作者: 三月ღ

一、下载JWT包

image

二、配置文件appsettings.json

"Auth": {
    "SecretKey":      		"al45jgioasdjgoije8343050945049jg3409jgfoksdjfglaskdjfaiosdjfasdfsd", 
    //私钥长度 16位以上
    "Issuer": "www.aaabb.com", //发行人
    "Audience": "www.ccdd.com" //访问人
  }

三、Program.cs中配置JWT

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    //返回的是 字符的数组
    var sercrtByte = Encoding.UTF8.GetBytes(builder.Configuration["Auth:SecretKey"]);
    //配置token验证
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
    {
        ValidateIssuer = true,
        ValidIssuer = builder.Configuration["Auth:Issuer"],
        ValidateAudience = true,
        ValidAudience = builder.Configuration["Auth:Audience"],
        //验证是否过期
        ValidateLifetime = true,
        //验证私钥
        IssuerSigningKey = new SymmetricSecurityKey(sercrtByte)

    };
});

开启Swagger认证

image

builder.Services.AddSwaggerGen(a =>
{
    #region 开启Swagger认证
    a.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {

        Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        BearerFormat = "JWT",
        Scheme = "Bearer"
    });

    a.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
    #endregion
});

必须开启以下中间件

//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();
//RequireAuthorization() 所有的控制器必须授权才能访问
app.MapControllers().RequireAuthorization();

四、创建TokenHelper.cs类生成令牌

  public class TokenHelper
    {
        private readonly IConfiguration _configuration;
        private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
        public TokenHelper(IConfiguration configuration, JwtSecurityTokenHandler jwtSecurityTokenHandler)
        {
            _configuration = configuration;
            _jwtSecurityTokenHandler = jwtSecurityTokenHandler;
        }
        /// <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken<T>(T user)
        {
            var signingAlogorithm = SecurityAlgorithms.HmacSha256;
            //CreateClaimList  将用户信息 加载到 载荷 当中
            var claimList = this.CreateClaimList(user);
            //Signature
            //取出私钥并以utf8编码字节输出
            var secretByte = Encoding.UTF8.GetBytes(_configuration["Auth:SecretKey"]);
            //使用非对称算法对私钥进行加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            //使用HmacSha256来验证加密后的私钥生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, signingAlogorithm);
            //生成Token
            var Token = new JwtSecurityToken(
          issuer: _configuration["Auth:Issuer"], //发布者
            audience: _configuration["Auth:Audience"], //接收者
            claims: claimList, //存放的用户信息
            notBefore: DateTime.UtcNow, //发布时间
            expires: DateTime.UtcNow.AddDays(1), //有效期设置为1天
            signingCredentials //数字签名
            );
            //生成字符串token
            var TokenStr = new JwtSecurityTokenHandler().WriteToken(Token);
            return TokenStr;
        }

        public T GetToken<T>(string Token)
        {
            Type t = typeof(T);
            //Activator.CreateInstance  根据 t(你传过来的泛型) 用反射的方式 new 当前对象 
            object objA = Activator.CreateInstance(t);
            var b = _jwtSecurityTokenHandler.ReadJwtToken(Token);
            foreach (var item in b.Claims)
            {
                PropertyInfo _Property = t.GetProperty(item.Type);
                if (_Property != null && _Property.CanRead)
                {
                    _Property.SetValue(objA, item.Value, null);
                }

            }
            return (T)objA;
        }
        /// <summary>
        /// 创建包含用户信息的CalimList
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private List<Claim> CreateClaimList<T>(T authUser)
        {
            var Class = typeof(T);
            //Claim 载荷的类 List
            List<Claim> claimList = new List<Claim>();
            //GetProperties 获取类型下所有的属性
            foreach (var item in Class.GetProperties())
            {
                //if (item.Name == "UPass")
                //{
                //    continue;
                //}
                claimList.Add(new Claim(item.Name, Convert.ToString(item.GetValue(authUser))));
            }
            return claimList;
        }
    }

五、登录时令牌在Headers里

image

  public UserController(TokenHelper tokenHelper)
  {
	TokenHelper = tokenHelper;
  }
  public TokenHelper TokenHelper { get; }
 	    /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public IActionResult Login(UserLoginDto dto)
        {
            var list = Users.Login(dto);
            Response.Headers["token"] = TokenHelper.CreateJwtToken(list);
            Response.Headers["Access-Control-Expose-Headers"] = "token";
            return Ok(list);
        }

前端vue code中

//登录方法  登录成功
//获取headers令牌存到sessionStorage
let token = res.headers["token"];
sessionStorage.setItem("token", token);
---------------------------------------------------
src/main.js中
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  let token = sessionStorage.getItem('token');
  if (token != null) {
    //将token 放到你的请求头上
    config.headers.Authorization = 'Bearer ' + token;
  }
  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});
------------------------------------------------------
外加路由守卫在src/router/index.js
router.beforeEach((to, from, next) => {
  //业务逻辑在这里执行
  //to.path 你要访问的这个地址是 登录页面
  if (to.path == '/') next();
  else {
    //获取token
    let token = sessionStorage.getItem('token');
    //如何存在  你也继续执行
    if (token != null) { next() }
    else { next({ path: '/' }) }    //不存在,跳转到登录页面
  }
})