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> {
new Claim(ClaimTypes.Name, name),
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()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
@ -214,6 +215,7 @@ namespace Blog.Core.Controllers
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, user.LoginName),
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()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

View File

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

View File

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

View File

@ -7,19 +7,24 @@ using Newtonsoft.Json;
using System;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Blog.Core.Common.HttpContextUser;
namespace Blog.Core.AuthHelper
{
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()
{
throw new NotImplementedException();
}
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.ContentType = "application/json";
@ -30,9 +35,16 @@ namespace Blog.Core.AuthHelper
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
Response.ContentType = "application/json";
Response.StatusCode = StatusCodes.Status403Forbidden;
await Response.WriteAsync(JsonConvert.SerializeObject((new ApiResponse(StatusCode.CODE403)).MessageModel));
if (_user.MessageModel != null)
{
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 System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Blog.Core.Common.HttpContextUser;
using Blog.Core.Model;
namespace Blog.Core.AuthHelper
{
@ -23,8 +26,11 @@ namespace Blog.Core.AuthHelper
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IRoleModulePermissionServices _roleModulePermissionServices;
private readonly IHttpContextAccessor _accessor;
private readonly ISysUserInfoServices _userServices;
private readonly IUser _user;
/// <summary>
/// 构造函数注入
@ -32,9 +38,13 @@ namespace Blog.Core.AuthHelper
/// <param name="schemes"></param>
/// <param name="roleModulePermissionServices"></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;
_userServices = userServices;
_user = user;
Schemes = schemes;
_roleModulePermissionServices = roleModulePermissionServices;
}
@ -74,6 +84,7 @@ namespace Blog.Core.AuthHelper
Role = item.Role?.Name.ObjToString(),
}).ToList();
}
requirement.Permissions = list;
}
@ -114,7 +125,6 @@ namespace Blog.Core.AuthHelper
//result?.Principal不为空即登录成功
if (result?.Principal != null || isTestCurrent)
{
if (!isTestCurrent) httpContext.User = result.Principal;
// 获取当前用户的角色信息
@ -160,6 +170,7 @@ namespace Blog.Core.AuthHelper
return;
}
// 判断token是否过期过期则重新登录
var isExp = false;
// ids4和jwt切换
// ids4
@ -172,18 +183,31 @@ namespace Blog.Core.AuthHelper
// 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;
}
if (isExp)
if (!isExp)
{
context.Succeed(requirement);
}
else
{
context.Fail();
context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
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;
}
}
//判断没有登录时是否访问登录的url,并且是Post请求并且是form表单提交类型否则为失败
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);
}
}
}
}

View File

@ -1,5 +1,4 @@

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