179 lines
7.6 KiB
C#
179 lines
7.6 KiB
C#
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").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
|
||
{
|
||
_logger.LogInformation("RefreshToken:我在刷新登录--1"+ logininfo.TokenInfo.Expired.ToString());
|
||
//2.判断缓存的token 过期时间
|
||
if (!string.IsNullOrEmpty(logininfo.TokenInfo.Token) && logininfo.TokenInfo.Expired.AddMinutes(-10) <= DateTime.Now)
|
||
{
|
||
_logger.LogInformation("RefreshToken:我在刷新登录--2");
|
||
var refreshtokeninfo = RefreshToken(logininfo.TokenInfo.Token, logininfo.TokenInfo.RefreshToken, loginService);
|
||
var info = _redisClientService.GetStringKey<LoginInDto>($"wms_login_{token}");
|
||
_logger.LogInformation("RefreshToken:我在刷新登录--完成:" + info.UserInfo.Nickname);
|
||
//刷新token后不能删除_redis用户缓存
|
||
//if (!refreshtokeninfo)
|
||
//{
|
||
// RemoveRedisLoginInfo(token);
|
||
//}
|
||
}
|
||
//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);
|
||
}
|
||
}
|
||
if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403)
|
||
{
|
||
//调用单点的退出接口
|
||
var dto = new LoginOutDto()
|
||
{
|
||
UcId = logininfo.UserInfo.UcId.ToString(),
|
||
SessionId = logininfo.UserInfo.SeesionId,
|
||
Token = logininfo.TokenInfo.Token,
|
||
AccessToken = logininfo.TokenInfo.PhpToken,
|
||
ExpiresIn = logininfo.TokenInfo.Expired
|
||
|
||
};
|
||
var res = await loginService.LoginOutAsync(dto);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
_logger.LogInformation("RefreshToken:我在刷新登录--3");
|
||
var res = _loginService.RefreshToken(OldToken, RefreshToken);
|
||
|
||
if (!res.Result.Success)
|
||
return false;
|
||
else
|
||
return true;
|
||
}
|
||
}
|
||
}
|