练习模板: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"
});
}

显示效果:

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

到这里相当于我们已将把锁制造出来了,但是还没有将锁装到门上面,且我们使用的是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"
});
});

 效果:

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

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


假如我们不加入认证:

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异常,表示未验证。

2.演示视频(不怎么会添加本地视频,百度好像要弄个链接才行,能看就行~):

Jwt验证登录的更多相关文章

  1. jwt验证登录信息

    为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...

  2. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十四║ Vuex + JWT 实现授权验证登录

    壹周回顾 哈喽,又是元气满满的一个周一,又与大家见面了,周末就是团圆节了,正好咱们的前后端也要团圆了,为什么这么说呢,因为以后的开发可能就需要前后端一起了,两边也终于会师了,还有几天Vue系列就基本告 ...

  3. spring boot:spring security整合jwt实现登录和权限验证(spring boot 2.3.3)

    一,为什么使用jwt? 1,什么是jwt? Json Web Token, 它是JSON风格的轻量级的授权和身份认证规范, 可以实现无状态.分布式的Web应用授权 2,jwt的官网: https:// ...

  4. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  5. flask验证登录学习过程(1)---准备

    对应flask的接口开发,目前自己可以熟练的进行.但是深入到更基础的,从注册到验证登录的过程一直不是特别清楚. 趁着年度不是特别忙的时候,特意去学习加强一下.把这个过程记录在此处. 首先是规划一个项目 ...

  6. webapi中使用token验证(JWT验证)

    本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...

  7. JWT实现登录认证实例

    JWT全称JSON Web Token,是一个紧凑的,自包含的,安全的信息交换协议.JWT有很多方面的应用,例如权限认证,信息交换等.本文将简单介绍JWT登录权限认证的一个实例操作. JWT组成 JW ...

  8. jwt以及如何使用jwt实现登录

    目录 jwt的使用和使用jwt进行登录 什么是jwt jwt的组成 为什么选择jwt session的缺点 jwt的优点 一个jwt的工具类 将jwt和登录进行结合 axios方式将jwt放在head ...

  9. 厉害!我带的实习生仅用四步就整合好SpringSecurity+JWT实现登录认证!

    小二是新来的实习生,作为技术 leader,我还是很负责任的,有什么锅都想甩给他,啊,不,一不小心怎么把心里话全说出来了呢?重来! 小二是新来的实习生,作为技术 leader,我还是很负责任的,有什么 ...

随机推荐

  1. BUAA_DS_北航数据结构:输出全排列

    输入一个数 \(n\),输出 \(1\sim n\) 的所有全排列,每个排列占一行,每个字符保留 \(5\) 个场宽.勤奋的同学一定已经开始打表了是吧. 说是能做肯定不是骗大家,那怎么做呢~ 其实回溯 ...

  2. python3 爬虫 Scrapy库学习1

    1生成项目:生成项目文件夹 scrapy startproject 项目名 2生成爬虫文件 scrapy genspider 爬虫名 指定域名 3进入items文件可以输入自己想要爬取的内容比如 te ...

  3. VUE开发--环境配置(一)(转)

    无剑_君关注 0.312019.05.09 11:53:43字数 1,073阅读 19,627        https://www.jianshu.com/p/a494417def99?utm_so ...

  4. ubuntu16 和ubuntu18安装及设置静态ip

    1.准备ubuntu16镜像2.安装:https://zhuanlan.zhihu.com/p/1447048653.安装ubuntu后,sudo passwd root这个命令建立root用户的密码 ...

  5. 什么是 Spring Cloud?

    Spring cloud 流应用程序启动器是 于 Spring Boot 的 Spring 集成应用程序,提供与外部系统的集成.Spring cloud Task,一个生命周期短暂的微服务框架,用于快 ...

  6. linux上使用nginx、uwsgi部署django项目

    参考:CentOS7下部署Django项目详细操作步骤 注意事项: 在虚拟环境中操作,虚拟环境中安装nginx.uwsgi,虚拟环境外需安装uwsgi -- 临时关闭防火墙:systemctl sto ...

  7. 面试问题之C++语言:Overload、Override及Overwirte的区别

    Overload(重载):在C++程序中,可以将语义.功能相似的几个函数用同一个名字表示,但参数或返回值不同(包括类型.顺序不同),即函数重载. 特点: (1)相同的范围(在同一个类中) (2)函数名 ...

  8. spring-boot 注解集合

    @Configuration 用于定义配置类,可替换XML配置文件,被注解的类内部包含一个或多个@Bean注解方法.可以被AnnotationConfigApplicationContext或者Ann ...

  9. Spring 对 DAO 的支持?

    Spring 对数据访问对象(DAO)的支持旨在简化它和数据访问技术如 JDBC, Hibernate or JDO 结合使用.这使我们可以方便切换持久层.编码时也不用担心 会捕获每种技术特有的异常.

  10. 学习Nginx(二)

    Nginx支持四层代理 http://nginx.org/en/docs/stream/ngx_stream_core_module.html 该ngx_stream_core_module模块自1. ...