1.在用户User表新加一个字段JWTVersions设置为long类型。
2.用户每登陆一次JWTVersion自动加一,并保存在数据库中且加入到jwt生成的token中;代码如下:
public async Task<ResultApi> Login(string username, string pwd)
{
User user =await userService.FindAsync(username);
user.Password = pwd;
if(user == null|| user.Password != pwd)
{
return ResultHelper.Error("用户名或密码错误");
}
else
{
user.JWTVersion++;
userService.EditByEntity(user);//保存到数据库中
return ResultHelper.Success(customJWTService.GetJwtToken(user));
}
}
在jwt生成中:加入JWTversion
...
UserRoleRelation userRoleRelation = userRoleService.FindAny(user.Id);
Role role = roleService.Find(userRoleRelation.RoleId);
string roleName = role.Name;
//payload
var claims = new Claim[]
{
new Claim("Id", user.Id.ToString()),
new Claim("Name",user.Name),
new Claim("PhoneNumber", user.PhoneNumber),
new Claim(ClaimTypes.Role,roleName),
new Claim("IsEnable", user.IsEnable.ToString()),
new Claim(ClaimTypes.Version,user.JWTVersion.ToString())
};
...
3.添加行为拦截器判断当前用户jwtversion与数据中jwtversion大小,如果数据的jwtversion大于当初用户,则用户登陆失效。
public class JWTValidationFilter : IAsyncActionFilter
{
private readonly UserService userService;
private readonly IMemoryCache cache;
public JWTValidationFilter(IMemoryCache cache, UserService userService)
{
this.cache = cache;
this.userService = userService;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var value = context.HttpContext.User.FindFirst("id");
if (value == null)
{
await next();
return;
}
Guid id =new Guid(value.Value);
string chacheKey = $"JWTVaildationFilter.UserInfo.{id}";
Model.Entitys.User user = await cache.GetOrCreateAsync(chacheKey, async e =>
{
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5);
return userService.Find(id);
});
if (user == null)
{
var result = new ObjectResult($"UserId{id} not found");
result.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result=result;
return;
}
var claimVersion = context.HttpContext.User.FindFirst(ClaimTypes.Version);
long jwtVerOfReq = long.Parse(claimVersion!.Value);
if (jwtVerOfReq >= user.JWTVersion)
{
await next();
}
else
{
var result = new ObjectResult($"jwtversion mismatch,如:在其他地方登录");
result.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = result;
return;
}
}
}
4.在program注册服务
builder.Service.Configure<MvcOptions>(op =>{
op.Filters.Add<>();
});