You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在ASP.NET Core MVC中实现多窗口异步登出的技术求助

多窗口登出功能实现的C#技术求助

我正在使用C#和ASP.NET Core MVC,通过AuthController实现应用所有打开窗口的登出功能。已在NotifyClient.cs中定义异步方法完成请求,也在公共接口配置了对应任务,功能接近实现,但对代码执行流程存疑,需要C#技术支持。

现有代码

AuthController代码

public async Task<IActionResult> Logout(string application, Boolean notifyWindows, string callback = "/")
{
    if (HttpContext.Request.Cookies.Count > 0)
    {
        var siteCookies = HttpContext.Request.Cookies.Where(c => c.Key.Contains(".AspNetCore.") || c.Key.Contains("Microsoft.Authentication"));

        foreach (var cookie in siteCookies)
        {
            Response.Cookies.Delete(cookie.Key);
        }
    }

    if (notifyWindows == true)
    {
        // todo, get user id
        // todo, call the notification endpoint to inform the FE to logout of all tabs
        // await _notifyClient.UpdateUserLogoutAsync(new UpdateUserLogoutRequest { }, ct);
        _logger.LogError("notifyWindows");
    }

    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    HttpContext.Session.Clear();

    return RedirectToAction("Auth0Login", new { callback, application, forceLogin = true });
}

NotifyClient代码

public async Task UpdateUserLogoutAsync(UpdateUserLogoutRequest request)
{
    // try
    // {
    //    var message = new HttpRequestMessage(HttpMethod.Post, $"realtimealerts/user/logout/{request.UserId}");
    //    message.Content =
    //        new 
    // }

    // TODO NEW FUNCTION TO LOGOUT 
    // UpdateUserLogoutAsync
}

INotifyClient代码

public interface INotifyClient
{
    Task UpdateUserLogoutAsync(UpdateUserLogoutRequest request);
}

待解决问题

  • 如何获取当前登录用户的ID
  • 完善NotifyClient中UpdateUserLogoutAsync方法的HTTP请求实现
  • 优化登出流程的执行顺序,确保逻辑正确

完整实现方案

1. 获取当前用户ID

在AuthController中通过HttpContext.User的Claims获取用户ID,示例如下:

// 需引用System.Security.Claims
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);

如果使用Auth0等第三方认证,可替换为对应Claim的Key,比如User.FindFirstValue("sub")。

2. 完善NotifyClient的HTTP请求实现

注入HttpClient完成POST请求,并添加异常处理:

private readonly HttpClient _httpClient;
private readonly ILogger<NotifyClient> _logger;

// 构造函数注入依赖
public NotifyClient(HttpClient httpClient, ILogger<NotifyClient> logger)
{
    _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    // 建议在Program.cs中配置HttpClient的BaseAddress,而非硬编码
}

public async Task UpdateUserLogoutAsync(UpdateUserLogoutRequest request, CancellationToken ct = default)
{
    if (request == null) throw new ArgumentNullException(nameof(request));
    if (string.IsNullOrEmpty(request.UserId)) throw new ArgumentException("用户ID不能为空", nameof(request.UserId));

    try
    {
        var requestUrl = $"realtimealerts/user/logout/{request.UserId}";
        // 若需要发送请求体,可使用JsonContent.Create(请求体对象)替代null
        var response = await _httpClient.PostAsync(requestUrl, null, ct);
        
        // 确保请求成功,失败则抛出异常
        response.EnsureSuccessStatusCode();
        _logger.LogInformation("已成功通知用户{UserId}的所有窗口登出", request.UserId);
    }
    catch (HttpRequestException ex)
    {
        _logger.LogError(ex, "发送用户{UserId}登出通知时出现HTTP错误", request.UserId);
        throw; // 可根据业务需求选择是否抛出或静默处理
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "发送用户{UserId}登出通知时出现未知错误", request.UserId);
        throw;
    }
}

3. 调整AuthController的登出流程顺序

优化执行顺序,确保核心登出逻辑优先执行,通知逻辑不阻塞主流程:

public async Task<IActionResult> Logout(string application, bool notifyWindows, string callback = "/", CancellationToken ct = default)
{
    // 获取当前用户ID
    var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrEmpty(userId))
    {
        _logger.LogWarning("无法获取当前用户ID");
    }

    // 执行核心登出操作
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme, ct);
    
    // 清理遗留认证Cookie(SignOutAsync通常会自动处理,此步骤为冗余保障)
    if (HttpContext.Request.Cookies.Count > 0)
    {
        var siteCookies = HttpContext.Request.Cookies.Where(c => 
            c.Key.Contains(".AspNetCore.") || c.Key.Contains("Microsoft.Authentication"));

        foreach (var cookie in siteCookies)
        {
            var cookieOptions = new CookieOptions
            {
                Expires = DateTimeOffset.UtcNow.AddDays(-1),
                Path = "/",
                Domain = Request.Host.Host // 跨域场景需配置正确的Domain
            };
            Response.Cookies.Delete(cookie.Key, cookieOptions);
        }
    }

    // 清理Session
    HttpContext.Session.Clear();

    // 通知前端所有窗口登出
    if (notifyWindows && !string.IsNullOrEmpty(userId))
    {
        try
        {
            await _notifyClient.UpdateUserLogoutAsync(
                new UpdateUserLogoutRequest { UserId = userId }, 
                ct);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知前端用户{UserId}登出失败", userId);
            // 此处可选择不抛出异常,避免影响主登出流程
        }
    }

    return RedirectToAction("Auth0Login", new { callback, application, forceLogin = true });
}

4. 补充依赖配置

  • 确保UpdateUserLogoutRequest类定义正确:
public class UpdateUserLogoutRequest
{
    public string UserId { get; set; }
}
  • 在Program.cs中注册HttpClient和INotifyClient:
builder.Services.AddHttpClient<INotifyClient, NotifyClient>(client =>
{
    client.BaseAddress = new Uri("https://你的实时告警API域名/");
});

内容的提问来源于stack exchange,提问作者Need Help

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:12:46