fix(auth): 解决登录登出流程中的Cookie管理和令牌验证问题
- 在登录页面访问时记录所有Cookie信息并优化清除逻辑 - 登录处理时添加详细的请求日志记录 - 登出时先删除可能存在的旧Token避免黑名单影响 - 完善登出时的Cookie清除机制,清除所有Cookie确保安全 - 优化中间件中的令牌黑名单检查和异常处理 - 添加响应头确保浏览器正确清除缓存 - 改进日志记录的详细程度便于问题排查
This commit is contained in:
@@ -36,15 +36,21 @@ namespace YLErp.Web.Controllers
|
||||
{
|
||||
var logger = LogFactory.GetLogger<AccountController>();
|
||||
var remoteIp = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
logger.Info($"[登录页面] 访问登录页,IP: {remoteIp}, skipSso: {skipSso}");
|
||||
|
||||
// 记录所有 Cookie
|
||||
var allCookies = Request.Cookies.Select(c => $"{c.Key}={(c.Value?.Length > 10 ? c.Value?.Substring(0, 10) + "..." : c.Value)}").ToList();
|
||||
var hasAccessToken = Request.Cookies.ContainsKey("Access-Token");
|
||||
logger.Info($"[登录页面] 访问登录页,IP: {remoteIp}, skipSso: {skipSso}, HasAccessToken: {hasAccessToken}, Cookies: [{string.Join(", ", allCookies)}]");
|
||||
|
||||
var keys = Request.Cookies.Keys.ToArray();
|
||||
logger.Info($"[登录页面] 清除 {keys.Length} 个 Cookie(保留 {_auth_login})");
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (key != _auth_login)
|
||||
{
|
||||
Response.Cookies.Delete(key);
|
||||
logger.Info($"[登录页面] 删除 Cookie: {key}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +119,13 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost, ResponseCache(NoStore = true)]
|
||||
public async Task<IActionResult> LoginHandle(LogOnModel model)
|
||||
{
|
||||
var logger = LogFactory.GetLogger<AccountController>();
|
||||
var hasToken = Request.Cookies.ContainsKey("Access-Token");
|
||||
logger.Info($"[登录处理] 收到登录请求 - UserName: {model?.UserName}, HasAccessToken: {hasToken}");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(model?.UserName) || string.IsNullOrWhiteSpace(model?.Password))
|
||||
{
|
||||
logger.Info("[登录处理] 用户名或密码为空");
|
||||
return LoginError("用户名和密码必须填写");
|
||||
}
|
||||
|
||||
@@ -249,6 +260,10 @@ namespace YLErp.Web.Controllers
|
||||
|
||||
await HttpContext.SignInAsync(AuthHelper.CookieAuthType, new ClaimsPrincipal(identity));
|
||||
|
||||
// 先删除可能存在的旧Token(避免黑名单影响)
|
||||
Response.Cookies.Delete("Access-Token");
|
||||
Response.Cookies.Delete("Access-Token-Encrypt");
|
||||
|
||||
var jwtToken = AuthHelper.CreateJwtToken2(identity);
|
||||
Response.Cookies.Append("Access-Token", jwtToken, new CookieOptions
|
||||
{
|
||||
@@ -274,7 +289,9 @@ namespace YLErp.Web.Controllers
|
||||
var loginName = User.GetUserName();
|
||||
var remoteIp = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
|
||||
logger.Info($"[退出登录] 用户请求退出 - UserId: {userId}, LoginName: {loginName}, IP: {remoteIp}");
|
||||
// 记录所有 Cookie
|
||||
var allCookies = Request.Cookies.Select(c => $"{c.Key}={c.Value?.Substring(0, Math.Min(10, c.Value?.Length ?? 0))}...").ToList();
|
||||
logger.Info($"[退出登录] 用户请求退出 - UserId: {userId}, LoginName: {loginName}, IP: {remoteIp}, Cookies: [{string.Join(", ", allCookies)}]");
|
||||
|
||||
if (userId > 0)
|
||||
{
|
||||
@@ -336,10 +353,13 @@ namespace YLErp.Web.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// 清除 JWT Token Cookie(在加入黑名单之后)
|
||||
Response.Cookies.Delete("Access-Token");
|
||||
Response.Cookies.Delete("Access-Token-Encrypt");
|
||||
logger.Info($"[退出登录] JWT Token Cookie 已清除");
|
||||
// 清除所有 Cookie(确保旧Token不会带到登录页面)
|
||||
var keys = Request.Cookies.Keys.ToArray();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
Response.Cookies.Delete(key);
|
||||
}
|
||||
logger.Info($"[退出登录] 所有 Cookie 已清除,共 {keys.Length} 个");
|
||||
|
||||
if (SsoLoginConfig.SSO_Enable)
|
||||
{
|
||||
@@ -356,7 +376,13 @@ namespace YLErp.Web.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info($"[退出登录] 跳转到登录页");
|
||||
logger.Info($"[退出登录] 准备重定向到登录页,清除的Cookie数量: {keys.Length}");
|
||||
|
||||
// 添加响应头,确保浏览器清除Cookie
|
||||
Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
Response.Headers.Add("Pragma", "no-cache");
|
||||
Response.Headers.Add("Expires", "0");
|
||||
|
||||
return RedirectToAction("Login");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,25 +36,32 @@ namespace YLErp.Web.Middleware
|
||||
{
|
||||
// 获取当前请求路径
|
||||
var path = context.Request.Path.Value?.ToLowerInvariant() ?? "";
|
||||
var logger = LogFactory.GetLogger("RefreshTokenMiddleware");
|
||||
|
||||
// 记录请求信息
|
||||
var hasToken = context.Request.Cookies.TryGetValue("Access-Token", out var token);
|
||||
var tokenPreview = hasToken && token.Length > 20 ? token.Substring(0, 20) + "..." : token;
|
||||
logger.Info($"[中间件] 请求: {path}, HasToken: {hasToken}, TokenPreview: {tokenPreview}");
|
||||
|
||||
// 跳过登录相关页面和静态资源,避免黑名单Token影响登录流程
|
||||
// 注意:/account/login 包含 /account/loginhandle (POST登录请求)
|
||||
if (path.StartsWith("/account/login") ||
|
||||
path.StartsWith("/account/logout") ||
|
||||
path.StartsWith("/account/captcha") ||
|
||||
path.StartsWith("/account/sso") ||
|
||||
path.StartsWith("/account/callback") ||
|
||||
path.StartsWith("/account/callback") || // SSO回调地址
|
||||
path.StartsWith("/content/") ||
|
||||
path.StartsWith("/scripts/") ||
|
||||
path.StartsWith("/css/") ||
|
||||
path.StartsWith("/images/") ||
|
||||
path.StartsWith("/favicon.ico"))
|
||||
{
|
||||
logger.Info($"[中间件] 白名单跳过: {path}");
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有Access-Token
|
||||
if (context.Request.Cookies.TryGetValue("Access-Token", out var token))
|
||||
// 检查是否有Access-Token(使用已声明的token变量)
|
||||
if (hasToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -79,9 +86,10 @@ namespace YLErp.Web.Middleware
|
||||
|
||||
// 检查token是否在黑名单中
|
||||
var blacklisted = Server.CacheProvider.Get($"token_blacklist:{jti}");
|
||||
logger.Info($"[中间件] 黑名单检查 - JTI: {jti}, Blacklisted: {blacklisted != null}");
|
||||
if (blacklisted != null)
|
||||
{
|
||||
LogFactory.GetLogger("RefreshTokenMiddleware").Info($"[Token验证] Token已在黑名单中,拒绝访问 - JTI: {jti}");
|
||||
logger.Info($"[中间件] Token在黑名单中,拒绝访问 - JTI: {jti}, Path: {path}");
|
||||
context.Response.Cookies.Delete("Access-Token");
|
||||
context.Response.Cookies.Delete("Access-Token-Encrypt");
|
||||
context.Response.StatusCode = 401;
|
||||
@@ -162,7 +170,6 @@ namespace YLErp.Web.Middleware
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录其他异常
|
||||
var logger = LogFactory.GetLogger("RefreshTokenMiddleware");
|
||||
logger.Error($"[Token刷新] 未知错误 - Token: {token?.Substring(0, Math.Min(20, token?.Length ?? 0))}..., 异常类型: {ex.GetType().Name}", ex);
|
||||
Console.WriteLine($"Token refresh error: {ex.Message}");
|
||||
// 继续处理请求,不影响正常流程
|
||||
|
||||
Reference in New Issue
Block a user