我所使用的环境如下:
ASP.NET CORE 6.0
Furion 3.7.5
可能有些人还不知道这个Furion是什么东西,这里给出它的开发文档的连接,有兴趣的朋友可以了解一下这个框架。这个框架是对ASP.NET CORE框架的一个封装,使用起来挺方便的,值得推荐给大家。
开发文档链接:1.1 介绍 | Furion
参考:15. 安全鉴权 | Furion
一般情况下我们使用一个token来认证,但是这样的话有一个问题:服务端生成的token的有效期是固定的,默认20分钟。当用户在界面上操作了20分钟以后,这个token就失效了,系统会返回401认证失败,这个情况在我看来是不太合理的。比如用户在执行添加操作,在提交的时候告诉你认证失败了,重新登录后之前添加的内容就要重新写一次,那他肯定要抓狂了,嘴里骂着这是什么烂软件。
刷新token的有效期默认是30天,可以自定义
当我们用2个token来认证的时候,流程是这样的:用户登录成功后,返回2个token,一个是正常的token,一个是刷新token。每次请求时都带上这2个token(其实刷新token不用每次携带,只在正常token快失效的携带就可以了,这里需要前端做一个判断,如果前端不愿意判断,每次都携带也可以,只是多耗费一点流量罢了)。当token有效期过了,系统会判断有效期超过的时间是不是大于刷新token的有效期,如果大于就返回401(因为刷新token的有效期很长,所以这种情况基本不会发生,你添加一个数据会用30天吗?),反之则会刷新正常的token,把正常token的有效期延长,刷新token的有效期也会相应的延长。然后把这2个新token放到http的返回头里面,前端接收到这2个新的token之后,替换之前的token。
添加自定义认证代码:
var jwtSetOption = JWTHelper.SetValidParameter();
builder.Services.AddJwt(null,jwtSetOption);
设置JWT的认证参数:
public static JWTSettingsOptions SetValidParameter()
{
JWTSettingsOptions options = new JWTSettingsOptions()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = App.Configuration["JWTSettings:IssuerSigningKey"],
ValidateIssuer = true,
ValidIssuer = App.Configuration["JWTSettings:ValidIssuer"],
ValidateAudience = true,
ValidAudience = App.Configuration["JWTSettings:ValidAudience"],
ValidateLifetime = true,
Algorithm = SecurityAlgorithms.HmacSha256,
ClockSkew = 0
};
return options;
}
自定义认证:
public class JwtHandler : AppAuthorizeHandler
{
public override async Task HandleAsync(AuthorizationHandlerContext context)
{
if (JWTHelper.AutoRefreshToken(context))
await AuthorizeHandleAsync(context);
else
context.Fail();
}
}
JWTHelper.AutoRefreshToken这个函数是我封装的方法,这个方法的代码如下:
public static bool AutoRefreshToken(AuthorizationHandlerContext context)
{
return JWTEncryption.AutoRefreshToken(context,
context.GetCurrentHttpContext());
}
引用的命名空间:using Furion.DataEncryption;
生成刷新token,这个token参数就是调用JWTEncryption.Encrypt函数生成的正常的token,这里可以自定义刷新token的有效期:
JWTEncryption.GenerateRefreshToken(token);
代码就这么几行,但是这里有几个坑要填
1、AddJwt必须在AddControllers之前调用,不然自定义认证的HandleAsync函数就不会被调用。
2、在配置JWT认证参数的时候,参数配置是这样的:
"JWTSettings": {
"ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true
"IssuerSigningKey": "", // 密钥,string 类型,必须是复杂密钥,长度大于16
"ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true
"ValidIssuer": "", // 签发方,string 类型
"ValidateAudience": true, // 是否验证签收方,bool 类型,默认true
"ValidAudience": "", // 签收方,string 类型
"ValidateLifetime": true, // 是否验证过期时间,bool 类型,默认true,建议true
"ExpiredTime": 20, // 过期时间,long 类型,单位分钟,默认20分钟
"ClockSkew": 5, // 过期时间容错值,long 类型,单位秒,默认 5秒
"Algorithm": "HS256" // 加密算法,string 类型,默认 HS256
}
这里的参数名字不要去改,因为在JWTEncryption.AutoRefreshToken函数内部会读取这个配置,如果名字改了就读取不到了,读取不到就会使用默认的值。这个时候你可能就会奇怪,明明我在配置文件里配置的过期时间是60分钟,但是生成的新的token的过期时间变成了20分钟。我就是因为手贱改了配置参数的名称才发现了这个问题。