😎增加无效 Token 黑名单

This commit is contained in:
zuohuaijun 2025-02-04 16:33:49 +08:00
parent 11aea9c472
commit a0305e82d1
9 changed files with 46 additions and 26 deletions

View File

@ -82,9 +82,14 @@ public class CacheConst
public const string KeyOpenAccessNonce = "sys_open_access_nonce:"; public const string KeyOpenAccessNonce = "sys_open_access_nonce:";
/// <summary> /// <summary>
/// 登录黑名单 /// 用户黑名单
/// </summary> /// </summary>
public const string KeyBlacklist = "sys_blacklist:"; public const string KeyUserBlacklist = "sys_user_blacklist:";
/// <summary>
/// token黑名单
/// </summary>
public const string KeyTokenBlacklist = "sys_token_blacklist:";
/// <summary> /// <summary>
/// 系统配置缓存 /// 系统配置缓存

View File

@ -100,7 +100,7 @@ public class OnlineUserHub : Hub<IOnlineUserHub>
{ {
if (string.IsNullOrEmpty(Context.ConnectionId)) return; if (string.IsNullOrEmpty(Context.ConnectionId)) return;
var httpContext = Context.GetHttpContext(); //var httpContext = Context.GetHttpContext();
var user = await _sysOnlineUerRep.AsQueryable().Filter("", true).FirstAsync(u => u.ConnectionId == Context.ConnectionId); var user = await _sysOnlineUerRep.AsQueryable().Filter("", true).FirstAsync(u => u.ConnectionId == Context.ConnectionId);
if (user == null) return; if (user == null) return;

View File

@ -313,17 +313,17 @@ public class SysAuthService : IDynamicApiController, ITransient
}; };
} }
/// <summary> ///// <summary>
/// 获取刷新Token 🔖 ///// 获取刷新Token 🔖
/// </summary> ///// </summary>
/// <param name="accessToken"></param> ///// <param name="accessToken"></param>
/// <returns></returns> ///// <returns></returns>
[DisplayName("获取刷新Token")] //[DisplayName("获取刷新Token")]
public string GetRefreshToken([FromQuery] string accessToken) //public string GetRefreshToken([FromQuery] string accessToken)
{ //{
var refreshTokenExpire = _sysConfigService.GetRefreshTokenExpire().GetAwaiter().GetResult(); // var refreshTokenExpire = _sysConfigService.GetRefreshTokenExpire().GetAwaiter().GetResult();
return JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire); // return JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
} //}
/// <summary> /// <summary>
/// 退出系统 🔖 /// 退出系统 🔖
@ -334,9 +334,15 @@ public class SysAuthService : IDynamicApiController, ITransient
if (string.IsNullOrWhiteSpace(_userManager.Account)) if (string.IsNullOrWhiteSpace(_userManager.Account))
throw Oops.Oh(ErrorCodeEnum.D1011); throw Oops.Oh(ErrorCodeEnum.D1011);
// 增加无效Token黑名单
var tokenExpire = await _sysConfigService.GetTokenExpire();
var accessToken = _httpContextAccessor.HttpContext.Request.Headers.Authorization.ToString();
_sysCacheService.Set($"{CacheConst.KeyTokenBlacklist}{accessToken}", $"{_userManager.UserId}-{_userManager.Account}-{_userManager.RealName}-{DateTime.Now}", TimeSpan.FromMinutes(tokenExpire));
// 发布系统退出事件 // 发布系统退出事件
await _eventPublisher.PublishAsync(UserEventTypeEnum.Logout, _userManager); await _eventPublisher.PublishAsync(UserEventTypeEnum.Logout, _userManager);
// 退出Swagger/设置无效Token响应头
_httpContextAccessor.HttpContext.SignoutToSwagger(); _httpContextAccessor.HttpContext.SignoutToSwagger();
} }

View File

@ -222,7 +222,7 @@ public class SysConfigService : IDynamicApiController, ITransient
} }
/// <summary> /// <summary>
/// 获取 Token 过期时间 /// 获取 Token 过期时间/分钟
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[NonAction] [NonAction]
@ -234,7 +234,7 @@ public class SysConfigService : IDynamicApiController, ITransient
} }
/// <summary> /// <summary>
/// 获取 RefreshToken 过期时间 /// 获取 RefreshToken 过期时间/分钟
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[NonAction] [NonAction]

View File

@ -276,16 +276,16 @@ public class SysUserService : IDynamicApiController, ITransient
[NonAction] [NonAction]
private async Task SetUserBalckList(SysUser user, StatusEnum status) private async Task SetUserBalckList(SysUser user, StatusEnum status)
{ {
// 账号禁用则增加黑名单,账号启用则移除黑名单 // 禁用账号则增加黑名单,启用账号则移除黑名单
var sysCacheService = App.GetRequiredService<SysCacheService>(); var sysCacheService = App.GetRequiredService<SysCacheService>();
if (status != StatusEnum.Enable) if (status != StatusEnum.Enable)
{ {
sysCacheService.Set($"{CacheConst.KeyBlacklist}{user.Id}", $"{user.RealName}-{user.Phone}"); sysCacheService.Set($"{CacheConst.KeyUserBlacklist}{user.Id}", $"{user.RealName}-{user.Phone}");
await _sysOnlineUserService.ForceOffline(user.Id); // 强制账号下线 await _sysOnlineUserService.ForceOffline(user.Id); // 强制账号下线
} }
else else
{ {
sysCacheService.Remove($"{CacheConst.KeyBlacklist}{user.Id}"); sysCacheService.Remove($"{CacheConst.KeyUserBlacklist}{user.Id}");
} }
} }

View File

@ -7,7 +7,7 @@
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 当前登录用户 /// 当前登录用户信息
/// </summary> /// </summary>
public class UserManager : IScoped public class UserManager : IScoped
{ {

View File

@ -39,11 +39,20 @@ namespace Admin.NET.Web.Core
// var serviceProvider = context.GetCurrentHttpContext().RequestServices; // var serviceProvider = context.GetCurrentHttpContext().RequestServices;
using var serviceScope = _serviceProvider.CreateScope(); using var serviceScope = _serviceProvider.CreateScope();
// 若当前账号存在黑名单中则授权失败 // 验证账号黑名单有则授权失败
var sysCacheService = serviceScope.ServiceProvider.GetRequiredService<SysCacheService>(); var sysCacheService = serviceScope.ServiceProvider.GetRequiredService<SysCacheService>();
if (sysCacheService.ExistKey($"{CacheConst.KeyBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value}")) if (sysCacheService.ExistKey($"{CacheConst.KeyUserBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value}"))
{ {
context.Fail(); context.Fail(new AuthorizationFailureReason(this, "账号已经黑名单,请联系相关管理人员。"));
context.GetCurrentHttpContext().SignoutToSwagger();
return;
}
// 验证Token黑名单有则授权失败
var accessToken = httpContext.Request.Headers.Authorization.ToString();
if (sysCacheService.ExistKey($"{CacheConst.KeyTokenBlacklist}{accessToken}"))
{
context.Fail(new AuthorizationFailureReason(this, "Token已失效请重新登录。"));
context.GetCurrentHttpContext().SignoutToSwagger(); context.GetCurrentHttpContext().SignoutToSwagger();
return; return;
} }

View File

@ -30,7 +30,7 @@ public class SuperApiAop : DefaultSuperApiAop
throw Oops.Oh("没权限 Unauthorized"); throw Oops.Oh("没权限 Unauthorized");
//} //}
var accessToken = aopContext.HttpContext.Request.Headers["Authorization"].ToString(); var accessToken = aopContext.HttpContext.Request.Headers.Authorization.ToString();
var (isValid, tokenData, validationResult) = JWTEncryption.Validate(accessToken.Replace("Bearer ", "")); var (isValid, tokenData, validationResult) = JWTEncryption.Validate(accessToken.Replace("Bearer ", ""));
if (!isValid) if (!isValid)
throw Oops.Oh("Token 无效"); throw Oops.Oh("Token 无效");
@ -62,7 +62,7 @@ public class SuperApiAop : DefaultSuperApiAop
var api = aopContext.InterfaceInfo; var api = aopContext.InterfaceInfo;
var context = aopContext.HttpContext; var context = aopContext.HttpContext;
var accessToken = context.Request.Headers["Authorization"].ToString(); var accessToken = context.Request.Headers.Authorization.ToString();
if (!string.IsNullOrWhiteSpace(accessToken) && accessToken.StartsWith("Bearer ")) if (!string.IsNullOrWhiteSpace(accessToken) && accessToken.StartsWith("Bearer "))
accessToken = accessToken.Replace("Bearer ", ""); accessToken = accessToken.Replace("Bearer ", "");
var claims = JWTEncryption.ReadJwtToken(accessToken)?.Claims; var claims = JWTEncryption.ReadJwtToken(accessToken)?.Claims;

View File

@ -74,7 +74,7 @@
"vue-router": "^4.5.0", "vue-router": "^4.5.0",
"vue-signature-pad": "^3.0.2", "vue-signature-pad": "^3.0.2",
"vue3-tree-org": "^4.2.2", "vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.3.78", "vxe-pc-ui": "^4.3.79",
"vxe-table": "^4.10.0", "vxe-table": "^4.10.0",
"vxe-table-plugin-element": "^4.0.4", "vxe-table-plugin-element": "^4.0.4",
"vxe-table-plugin-export-xlsx": "^4.0.7", "vxe-table-plugin-export-xlsx": "^4.0.7",