Asp.Net Core 3.1 学习4、Web Api 中基于JWT的token验证及Swagger使用
2021-03-08 19:27
标签:file 接收 方案 serialize 依赖 fail html 反射 过期 JWT(JSON Web Token)是目前最流行的跨域身份验证解决方案,他的优势就在于服务器不用存token便于分布式开发,给APP提供数据用于前后端分离的项目。登录产生的 token的项目完全可以独立与其他项目。当用户访问登录接口的时候会返回一个token,然后访问其他需要登录的接口都会带上这个token,后台进行验证如果token是有效的我们就认为用户是正常登录的,然后我们可以从token中取出来一些携带的信息进行操作。当然这些携带的信息都可以通过其他额外的字段进行传递,但是用token传递的话,不用其他额外加其他字段了。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。 JWT是由三段信息构成的,将这三段信息文本用 第一部分我们称它为头部(header):声明类型,这里是jwt;声明加密的算法 通常直接使用 HMAC SHA256 第二部分我们称其为载荷(payload, 类似于飞机上承载的物品): iss:Token发布者 exp:过期时间 分钟 sub:主题 aud:Token接受者 nbf:在此之前不可用 iat:发布时间 jti:JWT ID用于标识该JWT 除以上默认字段外,我们还可以自定义私有字段,如下例: 第三部分是签证(signature):这个部分需要base64加密后的header和base64加密后的payload使用 在VS2019中新建一个Core Api程序 Core选3.1 然后在项目上添加一个Jwt文件夹帮助类,新建接口ITokenHelper,类:TokenHelper继承ITokenHelper,类JWTConfig,类TnToken JWTConfig:用来保存读取jwt相关配置 TnToken:存放Token 跟过期时间的类 ITokenHelper接口:token工具类的接口,方便使用依赖注入,很简单提供两个常用的方法 TokenHelper:实现类 ConfigureServices中: JwtBearerDefaults.AuthenticationScheme与AddJwtBearer();下载两个依赖即可。或者NuGet安装 appsettings中简单配置一下jwt相关的信息: Configure中去启用验证中间件: 在Controllers文件夹里面新建一个api 名字LoginTest UserDto接收类 ReturnModel 只是我自己封装的一个统一的接口返回格式标准 跨域上篇文章说了这里就不提了 我是用传统的MVC的一个启动页面 把Api启动起来 MVC也启动起来试试看 在JWT管网解码 现在说说怎么来验证前台传递的jwt,其实很简单,最主要的就是验证token的有效性和是否过期。在接口ITokenHelper中添加验证的两个方法 。TokenHelper中实现 ITokenHelper中添加 TokenHelper中添加 其中TokenType是返回类型成功失败 在api LoginTest中新增两个验证的方法 上面一个简单的验证和支持自定义验证的就写好了。下面带有状态的是让我们清楚的知道是什么状态请求登录的时候 或者请求数据的时候,是token过期还是说token没有获取到等等。 其前端请求代码 项目上新建一个文件夹Filter,在文件夹Filter里新建一个过滤器TokenFilter context.ActionArguments。这是前段请求的时候地址栏带上的参数 token=xxx;这种类型的,不是请求的参数 不然会报错; 把过滤器在startup中注入一下: 需要验证token的地方,直接加上这个过滤器即可 前台试试 请求上图的GetList1、初始JWT
1.1、JWT原理
1.2、JWT结构
.
链接一起就构成了Jwt字符串。就像这样:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbklEIjoiYWRtaW4iLCJuYmYiOjE1ODc4OTE2OTMsImV4cCI6MTU4NzkyNzY5MywiaXNzIjoiV1lZIiwiYXVkIjoiRXZlcnlUZXN0T25lIn0.-snenNVHrrKq9obN8FzKe0t99ok6FUm5pHv-P_eYc30
{
‘typ‘: ‘JWT‘,
‘alg‘: ‘HS256‘
}
{
"sub": "1234567890",
"name": "wyy",
"admin": true
}
.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret
组合加密,然后就构成了jwt的第三部分。2、生成Token
2.1、建立项目
///
///
///
///
2.2、在Startup中去配置jwt相关:
#region jwt配置
services.AddTransient
"JWTConfig": {
"Issuer": "WYY", //Token发布者
"Audience": "EveryTestOne", //Token接受者
"IssuerSigningKey": "WYY&YL889455200Sily", //秘钥可以构建服务器认可的token;签名秘钥长度最少16
"AccessTokenExpiresMinutes": "600" //过期时间 分钟
},
//启用认证中间件 要写在授权UseAuthorization()的前面
app.UseAuthentication();
2.3、一个简单的登录获取token
[EnableCors("AllowCors")]
[Route("api/[controller]/[action]")]
[ApiController]
public class LoginTestController : ControllerBase
{
private readonly ITokenHelper tokenHelper = null;
///
///
///
2.4、前端获取token
input type="hidden" id="tokenValue" name="tokenValue" value="" />
br />br />br />
span>Token:span>div id="txtval">div>br />
span>有效期:span>div id="txtvalTime">div>br />
div>
input type="button" value="获取Token" onclick="getToken()" />br />br />br />
div>
script src="~/Scripts/jquery-3.3.1.js">script>
script type="text/javascript">
//获取token
function getToken() {
var data = JSON.stringify({ LoginID: "admin", Password: "admin888" });
$.ajax({
type: "post",
url: "https://localhost:44331/api/LoginTest/Login",
dataType: "json",
async: true,
data: data,
contentType: ‘application/json‘,
success: function (data) {
console.log(data);
$("#txtval").html(data.tnToken.tokenStr);
$("#txtvalTime").html(new Date(data.tnToken.expires).Format("yyyy-MM-dd hh:mm"));
$("#tokenValue").val(data.tnToken.tokenStr);
},
error: function (data) {
console.log("错误" + data);
}
});
}
Date.prototype.Format = function (fmt) { //author: zhengsh 2016-9-5
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
script>
3、验证前端传递的token
///
///
public enum TokenType
{
Ok,
Fail,
Expired
}
///
ValiTokenState第三个参数我还更了一个系统委托,是这样想的,处理可以验证token,还可以顺便取一个想要的数据,当然其实这样把相关逻辑混到一起也增加代码的耦合性,当时可以提高一点效率不用在重新解析一次数据,当然这个数据也可以通前台传递过来,所以怎么用还是看实际情况,这里只是封装一下提供这样一个方法,用的时候也可以用。
$.ajax({
type: "post",
url: "https://localhost:44331/api/LoginTest/ValiToken?tokenStr="+ $("#tokenValue").val(),
dataType: "json",
async: true,
data: { token: $("#tokenValue").val() },
contentType: ‘application/json‘,
success: function (data) {
console.log(data);
},
error: function (data) {
console.log("错误" + data);
}
});
4、Api中过滤器实现通用token验证
namespace JWTToken.Filter
{
public class TokenFilter : Attribute, IActionFilter
{
private ITokenHelper tokenHelper;
public TokenFilter(ITokenHelper _tokenHelper) //通过依赖注入得到数据访问层实例
{
tokenHelper = _tokenHelper;
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
ReturnModel ret = new ReturnModel();
//获取token
object tokenobj = context.ActionArguments["token"];
if (tokenobj == null)
{
ret.Code = 201;
ret.Msg = "token不能为空";
context.Result = new JsonResult(ret);
return;
}
string token = tokenobj.ToString();
string userId = "";
//验证jwt,同时取出来jwt里边的用户ID
TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == "WYY" && a["aud"] == "EveryTestOne", action => { userId = action["userId"]; });
if (tokenType == TokenType.Fail)
{
ret.Code = 202;
ret.Msg = "token验证失败";
context.Result = new JsonResult(ret);
return;
}
if (tokenType == TokenType.Expired)
{
ret.Code = 205;
ret.Msg = "token已经过期";
context.Result = new JsonResult(ret);
}
if (!string.IsNullOrEmpty(userId))
{
//给控制器传递参数(需要什么参数其实可以做成可以配置的,在过滤器里边加字段即可)
//context.ActionArguments.Add("userId", Convert.ToInt32(userId));
}
}
}
}
services.AddScoped
input type="hidden" id="tokenValue" name="tokenValue" value="" />
br />br />br />
span>Token:span>div id="txtval">div>br />
span>有效期:span>div id="txtvalTime">div>br />
div>
input type="button" value="获取Token" onclick="getToken()" />br />br />br />
div>
input type="button" value="获取List" onclick="getList()" />br />
script src="~/Scripts/jquery-3.3.1.js">script>
script type="text/javascript">
//获取token
function getToken() {
var data = JSON.stringify({ LoginID: "admin", Password: "admin888" });
$.ajax({
type: "post",
url: "https://localhost:44331/api/LoginTest/Login",
dataType: "json",
async: true,
data: data,
contentType: ‘application/json‘,
success: function (data) {
console.log(data);
$("#txtval").html(data.tnToken.tokenStr);
$("#txtvalTime").html(new Date(data.tnToken.expires).Format("yyyy-MM-dd hh:mm"));
$("#tokenValue
上一篇:【终极解决方案】为应用程序池“XXX”提供服务的进程在与 Windows Process Activation Service 通信时出现严重错误。该进程 ID 为“XXXX”。数据字段包含错误号。
文章标题:Asp.Net Core 3.1 学习4、Web Api 中基于JWT的token验证及Swagger使用
文章链接:http://soscw.com/index.php/essay/61943.html