Jwt验证登录

  • Jwt验证登录已关闭评论
  • 192 次浏览
  • A+
所属分类:.NET技术
摘要

练习模板(只包含了Swagger,Jwt可以直接练手):https://gitee.com/zh1446802857/swagger-multi-version-api.git

练习模板(只包含了Swagger,Jwt可以直接练手):https://gitee.com/zh1446802857/swagger-multi-version-api.git


Jwt在我的 认知里,是一套门锁。别人(用户)需要用到你的接口 的时候需要通过这个身份识别才可以使用。就像是一间房子,只有有钥匙的人才能进入。

项目开始

1新建一个类库(可复用)

  1. 新建一个Molde类,包含你的Token所携带的信息,例如我的:TokenModel
    using System;  namespace JwtCommon {     /// <summary>     /// Toekn令牌实体包含你所携带的Token信息     /// 作为登陆,我们包含账号,姓名,角色,密码即可     /// </summary>     public class TokenModel     {         /// <summary>         /// ID         /// </summary>         public int Id { get; set; }         /// <summary>         /// 姓名         /// </summary>         public string Name { get; set; }         /// <summary>         /// 角色         /// </summary>         public string Role { get; set; }         /// <summary>         /// 密码         /// </summary>         public string Pass { get; set; }         /// <summary>         /// 发行人         /// </summary>         public string iss { get; set; }         /// <summary>         /// 订阅人         /// </summary>         public string aud { get; set; }         /// <summary>         /// 密钥         /// </summary>         public string key { get; set; }     } }

获取Token  :假如我们要回家,要用钥匙打开门才能进去,不然就会拦在门外。与之相对应的,jwt验证。程序要调用某个接口的时候,要有一个"钥匙”即Token令牌     
创建一个方法实现创建Token功能   
引入Gti包:1:Microsoft.EXtensions.Confoguration 构造函数读取配置信息2:System.IdentityModel.Tokens.Jwt 对jwt操作
有三个参数会在多个地方使用,且应保持一致,因此将其写在配置文件当中 issuer(发行人),audience(订阅人),key(密钥:签署证书)

 "JWT": {     "iss": "NetCoreApi",//发行人(此项目)     "aud": "EveryOne",//订阅人(所有人)     "key": "IAmTheMostHandsomeInTheWorld"//秘钥(16位+)   }

 

CreateToken

public class JwtHelper     {        public string CreateToken(TokenModel tokenModel)         {             var claims = new List<Claim>()             {                 new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Id.ToString()),//Jti(Jwt Id,唯一标识)                 new Claim(JwtRegisteredClaimNames.Iss,tokenModel.iss),                 new Claim(JwtRegisteredClaimNames.Aud,tokenModel.aud),                 //nbf(not before)可以理解为:Token生效的时间,在你设定的生效时间之前Token是无效的                 new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),                 //exp(expiration time)过期时间,当前时间+你设置的过期时间                 new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(1)).ToUnixTimeSeconds()}"),                 //jwt发行时间,可以获取jwt年龄(能知道jwt什么吧                                                    时候开始工作的)                 new Claim(JwtRegisteredClaimNames.Iat,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),                 new Claim(ClaimTypes.Name,tokenModel.Name)//姓名             };             //假设有多个角色,批量添加(将role切割成多个角色,查询出每一个角色添加到claims中去)             claims.AddRange(tokenModel.Role.Split(',').Select(a => new Claim(ClaimTypes.Role, a)));              //设置密钥             var key68 = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenModel.key));             var keycode = new SigningCredentials(key68, SecurityAlgorithms.HmacSha256);             var jwt = new JwtSecurityToken(issuer: tokenModel.iss, claims: claims, signingCredentials: keycode);             var JwtToken = new JwtSecurityTokenHandler().WriteToken(jwt);             return JwtToken;         }     }

我们去控制器里调用这个方法,来得到Token,我的控制器叫EatDinnerController

CreateToken

#region [构造]         ///构造函数是为了得到Appsettinggs.json里的配置信息         public IConfiguration _configuration { get; }         public EatDinnerController(IConfiguration configuration)         {             _configuration = configuration;         }         #endregion          #region [全局变量]         JwtHelper _jwtHelper = new JwtHelper();         #endregion                  /// <summary>         /// 获取Token令牌         /// </summary>         /// <param name="name">姓名</param>         /// <param name="pass">密码</param>         /// <returns>Token令牌</returns>         [HttpGet]         [Route("GetToken")]         public string GetToken(string name, int pass)         {             //从配置信息读取ISS,AUD,KEY             var iss = _configuration["JWT:iss"];             var aud = _configuration["JWT:aud"];             var key = _configuration["JWT:key"];             return _jwtHelper.CreateToken(new TokenModel             {                 aud = aud,                 Id = (new Random().Next(10) + 1),//没有连接数据库,Id先随机任意的数字吧                 iss = iss,                 key = key,                 Name = name,                 Pass = pass.ToString(),                 Role = "Admin,User,Jack"             });         }

 

显示效果Jwt验证登录

 

运行结果:Jwt验证登录 
Response body里面的一长串字符就是我们要的结果eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMCIsImlzcyI6Ik5ldENvcmVBcGkiLCJhdWQiOiJFdmVyeU9uZSIsIm5iZiI6IjE2NTA3MDk5NjUiLCJleHAiOiIxNjUwNzEwMDI1IiwiaWF0IjoiMTY1MDcwOTk2NSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiLlvKDml6DmnoEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiQWRtaW4iLCJVc2VyIiwiSmFjayJdfQ.Cleaf-WuUhGUjYgPWhd7x7XVcCyqRhYvhf1vzsmRCBQ
拿到官网解析看看:红色对应代码里的加密类型及方案,紫色对应代码里的claims,蓝色则是密钥:IAmTheMostHandsomeInTheWorld

Jwt验证登录

到这里相当于我们已将把锁制造出来了,但是还没有将锁装到门上面,且我们使用的是swagger接口文档,则需引入一个get包SwashBuckle.AspNetCore.Filters

  随后应该在StartUp.cs 中ConfigureServices中的AddSwaggerGen服务中添加代码(Swagger服务内部

  1. 添加头部请求过滤器(添加之后会有一个头部请求的过滤器)
  2. 附加权限给所有的过滤器(给过滤器增加权限,如果没有对应的Token就无法通过)
  3. 把header添加Token且传入后台 
  4. 添加安全的定义来描述(初始化验证机制)
  1. Type:此过滤器的安全验证类型
  2. Description:描述
  3. In :token的位置
  4. Name:header传入Token对应的参数名
services.AddSwaggerGen(s =>             {                 //OperationFilter操作过滤器(验证)                 //AddResponseHeadersFilter添加头部请求过滤器                 //AppendAuthorizeToSummaryOperationFilter附加权限                 s.OperationFilter<AddResponseHeadersFilter>();                 s.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();                 //在header中添加Token传递给后台                 //SecurityRequirementsOperationFilter安全所需的                 s.OperationFilter<SecurityRequirementsOperationFilter>();                 //创建一个或者多个Security Definition(安全定义)描述你的api如何被保护的                 s.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme                 {                     Type = SecuritySchemeType.ApiKey,//安全方案/类型(模式)APIkey                     Description = "Jwt授权(数据在请求头中进行传输) n 请输入 Bearer {你的token(无需加括号,Bearer+空格+Token)}",                     In = ParameterLocation.Header,//In Api密钥的位置(即通过什么传输的——头部传输)                     Name = "JwtAuthoriza"                 });             });

 效果: Jwt验证登录

【此时,我们将锁添加在了门上】 

这时候还需要一个验证钥匙的配置,即Bearer认证:虽然我们有锁有钥匙(Token),但是在代码层次,还需要配置认证服务才能识别出Token的持有者身份,即鉴权(鉴定权限)


假如我们不加入认证:Jwt验证登录

No authenticationScheme was specified, and there was no DefaultChallengeScheme found. 译文:未指定authenticationScheme,也未找到DefaultChallengeScheme。

引入Get包:Microsoft.AspNetCore.Authentication.JwtBearer

依然是ConfigureServices方法//统一认证

 

统一的Bearer身份认证

  //统一Bearer授权认证             services.AddAuthentication(s =>             {                 //No authenticationScheme was specified, and there was no DefaultChallengeScheme found.                 //不写验证的时候刚才出现的两个单词,需要设置一下默认值先                 s.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;                 s.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;             }).AddJwtBearer(b =>             {                 #region 【获取配置信息】                 var iss = Configuration["JWT:iss"];                 var aud = Configuration["JWT:aud"];                 var key = Configuration["JWT:key"];                 //设置密钥                 var key68 = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));                 var keycode = new SigningCredentials(key68, SecurityAlgorithms.HmacSha256);                 #endregion                  b.TokenValidationParameters = new TokenValidationParameters                 {                     ValidateIssuerSigningKey = true,//是否验证对安全令牌签名的密钥验证(获取Token的时候设置了key)                     IssuerSigningKey = key68,//获取或设置用于签名验证的KEY                     ValidateAudience = true,                     ValidateIssuer = true,                     ValidIssuer = iss,                     ValidAudience = aud,                     ValidateLifetime = true,//验证有效期                     ClockSkew = TimeSpan.Zero,//时间偏移,可设置0                     RequireExpirationTime = true//获取或设置一个值,表示令牌是否必须拥有有效期                 };             });

 现在,钥匙有了。锁有了。验证钥匙和锁是否配对的方法也有了,现在只需要把钥匙插进去就OK了

配置官方认证中间件

app.UseRouting(); //一定要保持在UseRouting下面且顺序正确 app.UseAuthentication();//开启验证 app.UseAuthorization();//开启授权

效果演示:

1.首先不验证接口不会出现很长的错误,只会显示401异常,表示未验证。

Jwt验证登录 

 2.演示视频(点击观看)

引入的Get包

  1. Micrisoft.Extensions.Configuration(构造函数用)
  2. System.IdentityModel.Tokens.Jwt(生成Token时用)
  3. SwashBuckle.AspNetCore.Filters(设置身份验证的时候要用)
  4. Microsoft.AspNetCore.Authentication.JwtBearer(鉴权的时候要用)
    注意点1:建议红圈里的东西不要乱改,具体我也不是很清楚,好像是默认规则,如果有懂的大佬可以告诉一下我
    Jwt验证登录
    注意点2:看绿色圈住的,返回给定时间到现在经过的秒数,但是返回毫秒就不行,也是默认的规则吧,要注意

    Jwt验证登录