首页 > 解决方案 > 从 Blazor 中的控制器中清除 cookie

问题描述

我有一个通过 IdentityServer 进行身份验证的 Blazor 应用程序,当刷新令牌过期时,用户应该自动从应用程序中注销。当用户执行操作时,他们调用一个RequestHelper类,该类调用一个负责返回数据的网关。

这个RequestHelper类知道 Refresh 令牌何时过期并且可以向 LogoutController 发出请求。但是,以这种方式调用LogoutController时,不会从 IdentityServer 中清除 cookie 。如果用户导航到 /logout 那么它工作正常(cookie 被清除并且用户被重定向),但是当从RequestHelper调用LogoutController作为 HTTP 请求时,cookie 不会被清除并且用户不会被重定向,就像它是根本没有调用,但是确实到达了控制器。

public class RequestHelper : IRequestHelper
{
    private readonly TokenProvider _tokenProvider;
    private readonly AppContext _appContext;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;

    public RequestHelper(IHttpClientFactory clientFactory,
                         TokenProvider tokenProvider,
                         IConfiguration configuration,
                         AppContext appContext)
    {
        _tokenProvider = tokenProvider;
        _httpClientFactory = clientFactory;
        _configuration = configuration;
        _appContext = appContext;
    }

    public async Task<string> GetRequest(string url)
    {
        string jsonStringData = string.Empty;

        try
        {
            using (HttpClient client = _httpClientFactory.CreateClient("ServerAPI"))
            {
                var contentType = new MediaTypeWithQualityHeaderValue("application/json");
                client.DefaultRequestHeaders.Accept.Add(contentType);

                var token = _tokenProvider.AccessToken;
                if (!String.IsNullOrWhiteSpace(token) && client.DefaultRequestHeaders.Authorization == null)
                {
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token.Trim());
                }

                HttpResponseMessage response = await client.GetAsync(client.BaseAddress + url);
                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    TokenResponse tokenResponse = await RefreshAccessToken();

                    token = _tokenProvider.AccessToken;
                    if (!String.IsNullOrWhiteSpace(token))
                    {
                        client.DefaultRequestHeaders.Clear();
                        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token.Trim());
                        response = await client.GetAsync(client.BaseAddress + url);
                    }
                }

                jsonStringData = await response.Content.ReadAsStringAsync();
                client.DefaultRequestHeaders.Clear();
            }
        }
        catch (Exception ex)
        {
            jsonStringData = ex.Message;
        }

        return jsonStringData;
    }

    /// <summary>
    /// Requests a new token using the refresh token
    /// </summary>
    /// <returns></returns>
    private async Task<TokenResponse> RefreshAccessToken()
    {
        string authority = _configuration.GetValue("Authority", "https://localhost:44327");
        string currentUrl = _configuration.GetValue("CurrentUrl", "https://localhost:44367");
        using (HttpClient serverClient = _httpClientFactory.CreateClient())
        {
            var discoveryDocument = await serverClient.GetDiscoveryDocumentAsync(authority);
            var refreshToken = _tokenProvider.RefreshToken;
            using (HttpClient refreshTokenClient = _httpClientFactory.CreateClient())
            {
                TokenResponse tokenResponse = await refreshTokenClient.RequestRefreshTokenAsync(
                    new RefreshTokenRequest
                    {
                        Address = discoveryDocument.TokenEndpoint,
                        RefreshToken = refreshToken,
                        ClientId = "morpheusmanage",
                        ClientSecret = "secret"
                    });

                _tokenProvider.AccessToken = tokenResponse.AccessToken;
                _tokenProvider.RefreshToken = tokenResponse.RefreshToken;

                // Logout
                if (tokenResponse.RefreshToken == null)
                {
                    using (HttpClient logoutClient = _httpClientFactory.CreateClient())
                    {
                        await logoutClient.GetAsync(string.Format("{0}/logout", currentUrl));
                    }
                }

                return tokenResponse;
            }
        }
    }
}


public class LogoutController : Controller
{
    [HttpGet("logout")]
    public async Task Logout()
    {
        await HttpContext.SignOutAsync("Cookies");

        // Build redirect URI
        var request = HttpContext.Request;
        UriBuilder uriBuilder = new UriBuilder();
        uriBuilder.Scheme = request.Scheme;
        uriBuilder.Host = request.Host.Host;
        uriBuilder.Path = request.Path.ToString();
        uriBuilder.Port = request.Host.Port.GetValueOrDefault();
        uriBuilder.Query = request.QueryString.ToString();

        var prop = new AuthenticationProperties()
        {
            RedirectUri = uriBuilder.Uri.ToString()
        };
        await HttpContext.SignOutAsync("oidc", prop);
    }
}

重申控制器在浏览器上键入/logout Url 时会表现出预期的行为,但是当使用 HttpClient 从RequestHelper类调用时,它没有正确的行为。

标签: authentication.net-coreasp.net-identityblazor

解决方案


推荐阅读