using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WMS.Web.Core.Dto.Login; using WMS.Web.Domain.IService.Public; using WMS.Web.Domain.Services.Public; namespace WMS.Web.Repositories.DependencyInjection { /// /// token 黑名单中间件 /// public class AuthorizationTokenSecurityPolicy { private readonly RequestDelegate _next; private readonly IMemoryCache _cache; private ILogger _logger; private DateTime _refreshTime = DateTime.Now.AddYears(-5); private readonly RedisClientService _redisClientService; /// /// token黑名单中间件 /// /// /// public AuthorizationTokenSecurityPolicy(RequestDelegate next, ILogger logger, IMemoryCache cache, RedisClientService redisClientService) { _next = next; _cache = cache; this._logger = logger; _redisClientService = redisClientService; } /// /// 事件 /// /// /// public async Task Invoke(HttpContext context, ILoginService loginService) { string authorization = context.Request.Headers["Authorization"]; string path = context.Request.Path.Value.ToLower(); string[] pathlist = path.Split('/'); bool isLogin = pathlist.Where(x => x == "login" || x.ToLower() == "heart" || x.ToLower() == "test" || x.ToLower() == "serialnumber" || x.ToLower() == "barcode" || x.ToLower() == "swagger").Any(); if (isLogin) { context.Response.StatusCode = 200; await _next(context); return; } if (string.IsNullOrEmpty(authorization)) { context.Response.StatusCode = 401; var result = JsonConvert.SerializeObject(new { status = 401, data = string.Empty, message = "授权失败,请重新登录" }); context.Response.ContentType = "application/json;charset=utf-8"; await context.Response.WriteAsync(result); return; } else { string token = string.Empty; if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { token = authorization.Substring("Bearer ".Length).Trim(); } //判断前端过来的token if (string.IsNullOrEmpty(token)) { context.Response.StatusCode = 401; var result = JsonConvert.SerializeObject(new { status = 401, data = string.Empty, message = "授权失败,请重新登录" }); context.Response.ContentType = "application/json;charset=utf-8"; await context.Response.WriteAsync(result); return; } //1.验证是否有登录数据缓存 var logininfo = _redisClientService.GetStringKey($"wms_login_{token}"); if (logininfo == null) { context.Response.StatusCode = 401; var result = JsonConvert.SerializeObject(new { status = 401, data = string.Empty, message = "授权失败,请重新登录" }); context.Response.ContentType = "application/json;charset=utf-8"; await context.Response.WriteAsync(result); return; } else { //验证响应状态为401的就调用单点退出接口 if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403) { if (logininfo.UserInfo != null && logininfo.TokenInfo != null) { //调用单点的退出接口 var dto = new LoginOutDto() { UcId = logininfo.UserInfo.UcId.ToString(), SessionId = logininfo.UserInfo.SeesionId, Token = logininfo.TokenInfo.Token, RefreshToken = logininfo.TokenInfo.RefreshToken, AccessToken = logininfo.TokenInfo.PhpToken, ExpiresIn = logininfo.TokenInfo.Expired }; var res = await loginService.LoginOut(dto); return; } } DateTime now = DateTime.Now; TimeSpan jiange_timespan = TimeSpan.Zero; if (logininfo.TokenInfo.Expired < now) { jiange_timespan = now - logininfo.TokenInfo.Expired; var info = _redisClientService.GetStringKey($"wms_login_{token}"); if (info != null) { //超过16个小时的,就要移除缓存 if (jiange_timespan.TotalHours >= 16) _redisClientService.RemoveStringKey($"wms_login_{token}"); //超过1个小时的,就要刷新token else if (!string.IsNullOrEmpty(logininfo.TokenInfo.Token) && jiange_timespan.TotalHours >= 1) this.RefreshToken(logininfo.TokenInfo.Token, logininfo.TokenInfo.RefreshToken, loginService); } } //else //{ // //刷新token:距离过期时间还有10分钟就进行刷新token // jiange_timespan = logininfo.TokenInfo.Expired - now; // if (!string.IsNullOrEmpty(logininfo.TokenInfo.Token) && jiange_timespan.TotalMinutes<=10) // this.RefreshToken(logininfo.TokenInfo.Token, logininfo.TokenInfo.RefreshToken, loginService); //} //3.验证检查是否有黑名单的token缓存 string blacktoken = _redisClientService.GetStringKey($"wms_black_token_{logininfo.UserInfo.UcId}"); if (string.IsNullOrEmpty(blacktoken)) { context.Response.StatusCode = 200; await _next(context); } else { RemoveRedisLoginInfo(token); context.Response.StatusCode = 403; var result = JsonConvert.SerializeObject(new { status = 403, data = string.Empty, message = "拒绝用户证书试图访问此web站点,请与站点管理员联系以建立用户证书权限" }); context.Response.ContentType = "application/json;charset=utf-8"; await context.Response.WriteAsync(result); } } } } /// /// 过期,或者失效,移出token /// /// private void RemoveRedisLoginInfo(string token) { if (!string.IsNullOrEmpty(token)) { var info = _redisClientService.GetStringKey($"wms_login_{token}"); if (info != null) { _redisClientService.RemoveStringKey($"wms_login_{token}"); } } } /// /// 刷新token /// /// /// private bool RefreshToken(string OldToken, string RefreshToken, ILoginService _loginService) { var res = _loginService.RefreshTokenNew(OldToken, RefreshToken); if (!res.Result.Success) return false; else return true; } } }