Token 增加签名时间 🐛解决一个小bug MessageModel.success 赋值错误

1.解决用户修改关键信息后(如修改密码、修改名称等等) token不会失效
2.可解决用户修改部门、角色、权限后 token失效 只需要刷新User的修改时间
This commit is contained in:
LemonNoCry 2022-07-23 18:51:35 +08:00
parent 08464db50d
commit 03de3abe08
6 changed files with 77 additions and 35 deletions

View File

@ -160,6 +160,7 @@ namespace Blog.Core.Controllers
var claims = new List<Claim> { var claims = new List<Claim> {
new Claim(ClaimTypes.Name, name), new Claim(ClaimTypes.Name, name),
new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().Id.ToString()), new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().Id.ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) }; new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s))); claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
@ -214,6 +215,7 @@ namespace Blog.Core.Controllers
var claims = new List<Claim> { var claims = new List<Claim> {
new Claim(ClaimTypes.Name, user.LoginName), new Claim(ClaimTypes.Name, user.LoginName),
new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()), new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) }; new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s))); claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

View File

@ -2,6 +2,7 @@
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using Blog.Core.Model;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -70,6 +71,8 @@ namespace Blog.Core.Common.HttpContextUser
return new List<string>() { }; return new List<string>() { };
} }
public MessageModel<string> MessageModel { get; set; }
public IEnumerable<Claim> GetClaimsIdentity() public IEnumerable<Claim> GetClaimsIdentity()
{ {
var claims = _accessor.HttpContext.User.Claims.ToList(); var claims = _accessor.HttpContext.User.Claims.ToList();

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using Blog.Core.Model;
namespace Blog.Core.Common.HttpContextUser namespace Blog.Core.Common.HttpContextUser
{ {
@ -13,5 +14,7 @@ namespace Blog.Core.Common.HttpContextUser
string GetToken(); string GetToken();
List<string> GetUserInfoFromToken(string ClaimType); List<string> GetUserInfoFromToken(string ClaimType);
MessageModel<string> MessageModel { get; set; }
} }
} }

View File

@ -7,19 +7,24 @@ using Newtonsoft.Json;
using System; using System;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Blog.Core.Common.HttpContextUser;
namespace Blog.Core.AuthHelper namespace Blog.Core.AuthHelper
{ {
public class ApiResponseHandler : AuthenticationHandler<AuthenticationSchemeOptions> public class ApiResponseHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{ {
public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) private readonly IUser _user;
public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUser user) : base(options, logger, encoder, clock)
{ {
_user = user;
} }
protected override Task<AuthenticateResult> HandleAuthenticateAsync() protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
protected override async Task HandleChallengeAsync(AuthenticationProperties properties) protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{ {
Response.ContentType = "application/json"; Response.ContentType = "application/json";
@ -30,9 +35,16 @@ namespace Blog.Core.AuthHelper
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties) protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{ {
Response.ContentType = "application/json"; Response.ContentType = "application/json";
Response.StatusCode = StatusCodes.Status403Forbidden; if (_user.MessageModel != null)
await Response.WriteAsync(JsonConvert.SerializeObject((new ApiResponse(StatusCode.CODE403)).MessageModel)); {
Response.StatusCode = _user.MessageModel.status;
await Response.WriteAsync(JsonConvert.SerializeObject(_user.MessageModel));
}
else
{
Response.StatusCode = StatusCodes.Status403Forbidden;
await Response.WriteAsync(JsonConvert.SerializeObject((new ApiResponse(StatusCode.CODE403)).MessageModel));
}
} }
} }
} }

View File

@ -7,10 +7,13 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Blog.Core.Common.HttpContextUser;
using Blog.Core.Model;
namespace Blog.Core.AuthHelper namespace Blog.Core.AuthHelper
{ {
@ -23,8 +26,11 @@ namespace Blog.Core.AuthHelper
/// 验证方案提供对象 /// 验证方案提供对象
/// </summary> /// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; } public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IRoleModulePermissionServices _roleModulePermissionServices; private readonly IRoleModulePermissionServices _roleModulePermissionServices;
private readonly IHttpContextAccessor _accessor; private readonly IHttpContextAccessor _accessor;
private readonly ISysUserInfoServices _userServices;
private readonly IUser _user;
/// <summary> /// <summary>
/// 构造函数注入 /// 构造函数注入
@ -32,9 +38,13 @@ namespace Blog.Core.AuthHelper
/// <param name="schemes"></param> /// <param name="schemes"></param>
/// <param name="roleModulePermissionServices"></param> /// <param name="roleModulePermissionServices"></param>
/// <param name="accessor"></param> /// <param name="accessor"></param>
public PermissionHandler(IAuthenticationSchemeProvider schemes, IRoleModulePermissionServices roleModulePermissionServices, IHttpContextAccessor accessor) /// <param name="userServices"></param>
/// <param name="user"></param>
public PermissionHandler(IAuthenticationSchemeProvider schemes, IRoleModulePermissionServices roleModulePermissionServices, IHttpContextAccessor accessor, ISysUserInfoServices userServices, IUser user)
{ {
_accessor = accessor; _accessor = accessor;
_userServices = userServices;
_user = user;
Schemes = schemes; Schemes = schemes;
_roleModulePermissionServices = roleModulePermissionServices; _roleModulePermissionServices = roleModulePermissionServices;
} }
@ -74,6 +84,7 @@ namespace Blog.Core.AuthHelper
Role = item.Role?.Name.ObjToString(), Role = item.Role?.Name.ObjToString(),
}).ToList(); }).ToList();
} }
requirement.Permissions = list; requirement.Permissions = list;
} }
@ -114,7 +125,6 @@ namespace Blog.Core.AuthHelper
//result?.Principal不为空即登录成功 //result?.Principal不为空即登录成功
if (result?.Principal != null || isTestCurrent) if (result?.Principal != null || isTestCurrent)
{ {
if (!isTestCurrent) httpContext.User = result.Principal; if (!isTestCurrent) httpContext.User = result.Principal;
// 获取当前用户的角色信息 // 获取当前用户的角色信息
@ -160,6 +170,7 @@ namespace Blog.Core.AuthHelper
return; return;
} }
// 判断token是否过期过期则重新登录
var isExp = false; var isExp = false;
// ids4和jwt切换 // ids4和jwt切换
// ids4 // ids4
@ -172,18 +183,31 @@ namespace Blog.Core.AuthHelper
// jwt // jwt
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now; isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now;
} }
if (isExp)
if (!isExp)
{ {
context.Succeed(requirement); context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
}
else
{
context.Fail();
return; return;
} }
//校验签发时间
var value = httpContext.User.Claims.SingleOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
if (value != null)
{
var user = await _userServices.QueryById(_user.ID, true);
if (user.UpdateTime > value.ObjToDate())
{
_user.MessageModel = new ApiResponse(StatusCode.CODE403, "很抱歉,授权已失效,请重新授权").MessageModel;
context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.msg));
return;
}
}
context.Succeed(requirement);
return; return;
} }
} }
//判断没有登录时是否访问登录的url,并且是Post请求并且是form表单提交类型否则为失败 //判断没有登录时是否访问登录的url,并且是Post请求并且是form表单提交类型否则为失败
if (!(questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType))) if (!(questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType)))
{ {
@ -195,4 +219,4 @@ namespace Blog.Core.AuthHelper
//context.Succeed(requirement); //context.Succeed(requirement);
} }
} }
} }

View File

@ -1,5 +1,4 @@
 namespace Blog.Core.Model
namespace Blog.Core.Model
{ {
public class ApiResponse public class ApiResponse
{ {
@ -12,28 +11,28 @@ namespace Blog.Core.Model
switch (apiCode) switch (apiCode)
{ {
case StatusCode.CODE401: case StatusCode.CODE401:
{ {
Status = 401; Status = 401;
Value = "很抱歉,您无权访问该接口,请确保已经登录!"; Value = msg ?? "很抱歉,您无权访问该接口,请确保已经登录!";
} }
break; break;
case StatusCode.CODE403: case StatusCode.CODE403:
{ {
Status = 403; Status = 403;
Value = "很抱歉,您的访问权限等级不够,联系管理员!"; Value = msg ?? "很抱歉,您的访问权限等级不够,联系管理员!";
} }
break; break;
case StatusCode.CODE404: case StatusCode.CODE404:
{ {
Status = 404; Status = 404;
Value = "资源不存在!"; Value = "资源不存在!";
} }
break; break;
case StatusCode.CODE500: case StatusCode.CODE500:
{ {
Status = 500; Status = 500;
Value = msg; Value = msg;
} }
break; break;
} }
@ -41,7 +40,7 @@ namespace Blog.Core.Model
{ {
status = Status, status = Status,
msg = Value, msg = Value,
success = apiCode != StatusCode.CODE200 success = apiCode == StatusCode.CODE200
}; };
} }
} }
@ -54,5 +53,4 @@ namespace Blog.Core.Model
CODE404, CODE404,
CODE500 CODE500
} }
}
}