Почему форма POST с просроченным access_token приводит к GET при использовании промежуточного программного обеспечения Microsoft.AspNetCore.Authentication.OpenIdConnect
? Когда это происходит, любые данные, введенные в форму, теряются, так как они не достигают конечной точки HttpPost. Вместо этого запрос перенаправляется на тот же URI с GET, после перенаправления signin-oidc. Это ограничение, или у меня что-то настроено неправильно?
Я заметил эту проблему после сокращения AccessTokenLifetime с целью принудительного возобновления утверждений пользователя (т. Е. Если пользователь был отключен или у него былопретензии отозваны). Я воспроизводил это только тогда, когда для OpenIdConnectionOptions промежуточного программного обеспечения OpenIdConnectionOptions задано значение true options.UseTokenLifetime = true;
(установка этого значения на false приводит к тому, что утверждения аутентифицированного пользователя не обновляются должным образом).
Мне удалось воссоздать и продемонстрировать это поведениес помощью примера быстрого запуска IdentityServer4 5_HybridFlowAuthenticationWithApiAccess со следующими изменениями ниже. В основном, есть авторизованная форма, которая имеет HttpGet и метод HttpPost. Если вы дольше, чем AccessTokenLifetime (в этом примере настроено только 30 секунд), вместо метода HttpPost вызывается метод HttpGet.
Изменения MvcClient / Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
// the following was added
options.SlidingExpiration = false;
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("api1");
options.ClaimActions.MapJsonKey("website", "website");
// the following were changed
options.UseTokenLifetime = true;
options.Scope.Add("offline_access");
});
}
Изменения в списке клиентов в IdentityServer / Config.cs
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1",
IdentityServerConstants.StandardScopes.OfflineAccess,
},
AllowOfflineAccess = true,
// the following properties were configured:
AbsoluteRefreshTokenLifetime = 14*60*60,
AccessTokenLifetime = 30,
IdentityTokenLifetime = 15,
AuthorizationCodeLifetime = 15,
SlidingRefreshTokenLifetime = 60,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
UpdateAccessTokenClaimsOnRefresh = true,
RequireConsent = false,
}
Добавлено в MvcClient / Controllers / HomeController
[Authorize]
[HttpGet]
[Route("home/test", Name = "TestRouteGet")]
public async Task<IActionResult> Test()
{
TestViewModel viewModel = new TestViewModel
{
Message = "GET at " + DateTime.Now,
TestData = DateTime.Now.ToString(),
AccessToken = await this.HttpContext.GetTokenAsync("access_token"),
RefreshToken = await this.HttpContext.GetTokenAsync("refresh_token"),
};
return View("Test", viewModel);
}
[Authorize]
[HttpPost]
[Route("home/test", Name = "TestRoutePost")]
public async Task<IActionResult> Test(TestViewModel viewModel)
{
viewModel.Message = "POST at " + DateTime.Now;
viewModel.AccessToken = await this.HttpContext.GetTokenAsync("access_token");
viewModel.RefreshToken = await this.HttpContext.GetTokenAsync("refresh_token");
return View("Test", viewModel);
}