Files
WMS-Api/src/WMS.Web.Repositories/DependencyInjection/AuthorizationTokenSecurityPolicy.cs
18942506660 8d17b858ee 增加授权
2024-06-14 09:48:58 +08:00

198 lines
8.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// token 黑名单中间件
/// </summary>
public class AuthorizationTokenSecurityPolicy
{
private readonly RequestDelegate _next;
private readonly IMemoryCache _cache;
private ILogger<AuthorizationTokenSecurityPolicy> _logger;
private DateTime _refreshTime = DateTime.Now.AddYears(-5);
private readonly RedisClientService _redisClientService;
/// <summary>
/// token黑名单中间件
/// </summary>
/// <param name="next"></param>
/// <param name="cache"></param>
public AuthorizationTokenSecurityPolicy(RequestDelegate next, ILogger<AuthorizationTokenSecurityPolicy> logger, IMemoryCache cache, RedisClientService redisClientService)
{
_next = next;
_cache = cache;
this._logger = logger;
_redisClientService = redisClientService;
}
/// <summary>
/// 事件
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
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<LoginInDto>($"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<LoginInDto>($"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);
}
}
}
}
/// <summary>
/// 过期或者失效移出token
/// </summary>
/// <param name="token"></param>
private void RemoveRedisLoginInfo(string token)
{
if (!string.IsNullOrEmpty(token))
{
var info = _redisClientService.GetStringKey<LoginInDto>($"wms_login_{token}");
if (info != null)
{
_redisClientService.RemoveStringKey($"wms_login_{token}");
}
}
}
/// <summary>
/// 刷新token
/// </summary>
/// <param name="RefreshToken"></param>
/// <returns></returns>
private bool RefreshToken(string OldToken, string RefreshToken, ILoginService _loginService)
{
var res = _loginService.RefreshTokenNew(OldToken, RefreshToken);
if (!res.Result.Success)
return false;
else
return true;
}
}
}