authentication - 从 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类调用时,它没有正确的行为。
解决方案
推荐阅读
- python - 仅比较具有相同日期时间索引的列值
- php - 警告:需要(/home1/mokwattr/public_html/wp-includes/version.php)
- c# - C# 类库或 Web API
- ajax - 在 selenium 中处理网页对话框
- charts - Yii2 ChartJs 抛出 A non-numeric value 在页面遇到错误
- python - How to create a signed s3 url for requester pays bucket in python
- javascript - 如何在 vue js 中绘制图像
- html - Chrome 不呈现 HTML 内容?
- json - JQ 对 JSON 中的整数值进行排序
- javascript - 如何将连接按钮值添加到 api