Я создаю ASP. NET Core 3.1 серверное веб-приложение Blazor для клиентского компонента, отдельный ASP. NET Core 3.1 API для серверной службы данных и отдельный ASP . NET Реализация IdentyServer4 на основе Core 3.1 в качестве поставщика услуг идентификации.
Все работает, как я ожидаю, за исключением следующего:
После того, как пользователь вошел в систему и получил доступ к данным из API, через некоторое время веб-клиент больше не может получить доступ к API потому что я получаю 401 обратно от вызова API, указывающего, что срок действия маркера доступа истек. Пользователь все еще вошел в систему, и веб-приложение, похоже, автоматически обновляет токен oid c, но для API истекает срок действия access_token.
Я просматривал некоторые сообщения SO, в которых говорится о проверить дату истечения срока действия токена доступа и, если он истек, получить новый access_token от провайдера ID. Но примеры кода для более старых версий ASP. NET Core и использования angular для клиента, а не на стороне сервера Blazor.
Итак, сначала я хочу подтвердить, что не существует встроенного метода для автоматического обновления access_token после истечения срока действия. Если нет, то каков будет лучший способ продления просроченного access_token в моем сценарии.
В этом SO post говорится о процессе проверки значения "expires_at" в токене и, если оно истекло по сравнению с текущим DateTime, вызовите новый access_token. Но пример кода основан на клиенте MVC / Ajax. Я пытаюсь выяснить, есть ли что-нибудь встроенное в ASP. NET Core 3.1 с серверной Blazor, которое я могу использовать для процесса обновления токена доступа. Если нет, может ли кто-нибудь предоставить текущий лучший пример того, как обновить маркер доступа?
В IdentityServer4, Config.cs, для веб-клиента, у меня есть следующее в методе stati c IEnumerable Clients ;
new Client
{
ClientId = "myweb",
ClientName = "Client for My Web",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets = { new Secret("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".Sha256()) },
RedirectUris = { "https://mysite/signin-oidc" },
PostLogoutRedirectUris = { "https://mysite/signout-callback-oidc" },
AllowOfflineAccess = true,
RequireConsent = false,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
IdentityServerConstants.StandardScopes.Email,
"myapi"
}
}
и для клиента API у меня есть следующее:
new Client
{
ClientId = "myapi",
ClientName = "Client for MyAPI",
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowAccessTokensViaBrowser =true,
RequireConsent = false,
RedirectUris = { "https:myapi" },
PostLogoutRedirectUris = { "https://www.getpostman.com" },
AllowedCorsOrigins = {"https://www.getpostman.com"},
EnableLocalLogin = true,
AllowedScopes = { "myapi", "country" },
ClientSecrets =
{
new Secret("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".Sha256())
},
}
А вот моя конфигурация службы IdentityServer в методе Startup.cs -> ConfigureServices.
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.Authentication.CookieSlidingExpiration = true;
}).AddAspNetIdentity<ApplicationUser>();
В клиентском приложении Blazor на стороне сервера ASP. NET Core 3.1 у меня есть следующий код в службе:
public async Task<ODataProductsResponse> GetProducts(DataSourceRequest request, CancellationToken cancellationToken)
{
try
{
var baseUrl = $"{_utilities.GetBaseApiUrl()}/products?";
var requestUrl = $"{baseUrl}{request.ToODataString()}";
var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
var client = _httpClientFactory.CreateClient("MyApi");
var accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
if (accessToken != null)
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
}
var response = await client.SendAsync(requestMessage, cancellationToken);
if (response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
var oDataResponse = JsonSerializer.Deserialize<ODataProductsResponse>(body);
return oDataResponse;
}
throw new HttpRequestException("Request failed.");
//TODO: Parse error object and return to display error as an alert.
}
catch (Exception ex)
{
const string message =
"An exception has occurred while trying to get a list of Products from the API.";
_logger.LogError(ex, message);
throw;
//TODO: Add error object to result. Display to user as a HttpStatus 500
}
}
А вот моя конфигурация службы в Startup.cs -> метод ConfigureServices моего ASP. NET Core 3.1 веб-приложения.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
options.Authority = Configuration["IdentityProviderSettings:Authority"];
options.ClientId = Configuration["IdentityProviderSettings:ClientId"];
options.ClientSecret = Configuration["IdentityProviderSettings:ClientSecret"];
options.ResponseType = Configuration["IdentityProviderSettings:ResponseType"];
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("myapi");
options.Scope.Add("offline_access");
//options.CallbackPath = ...
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
});
Итак, я ищу пример кода, как наилучшим образом определить, что access_token имеет истек срок действия и, если да, то как запросить новый access_token, учитывая тот факт, что начальный access_token был получен как часть потока GrantTypes.Hybrid из IdentityServer4 (если это действительно имеет значение).
Или, если есть лучший способ продлить (или автоматически продлить?) Access_token в этом ASP. NET Core 3.1x сценарии.
Есть идеи?