gpt4 book ai didi

openid-connect - OpenIdDict(代码流)——处理访问 token 过期

转载 作者:行者123 更新时间:2023-12-05 08:07:17 28 4
gpt4 key购买 nike

我正在 ASP.Net Core 2.1 应用程序中进行重构,以从使用 SPA 的隐式流切换到使用 MVC 客户端应用程序的授权代码流。由于我们使用的是 OpenIDDict 库,因此我遵循了记录的 Code Flow Example这对于启动和运行来说非常棒,但我很快发现我的访问 token 即将过期并且(正如预期的那样)资源服务器开始拒绝请求。

我的问题是:如何最好地刷新访问 token ?

总的来说,我是 OpenID Connect 的新手,但我从大量可用资源中了解理论上的模式。措辞对我来说仍然有点不透明(grant、principal、scopes 等),但给出一个很好的例子,我相信我可以做到这一点。

提前致谢!

我尝试过的:

基于看似类似的问题,我尝试使用 Refresh Flow 实现刷新 token 流程来自上面同一来源的示例。虽然我相信我正确地设置了身份验证服务器管道,但我无法找到任何使用 C# 客户端的示例(上面的示例使用了角度应用程序)。

编辑:当我使用 refresh_token 授权向我的 token 端点发送帖子时,我正确地取回了一个新的访问 token 。我的问题是我不确定如何最好地从那里处理它。 GetTokenAsync 继续返回过时的 token 。

客户端启动:

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = new PathString("/signin");
})
.AddOpenIdConnect(options =>
{
// Note: these settings must match the application details
// inserted in the database at the server level.
options.ClientId = "Portal"; //TODO replace via configuration
options.ClientSecret = "---";

options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;

options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;

// Note: setting the Authority allows the OIDC client middleware to automatically
// retrieve the identity provider's configuration and spare you from setting
// the different endpoints URIs or the token validation parameters explicitly.
options.Authority = "https://localhost:57851"; //TODO replace via configuration

options.Scope.Add("email");
options.Scope.Add("roles");
options.Scope.Add("offline_access");

options.SecurityTokenValidator = new JwtSecurityTokenHandler
{
// Disable the built-in JWT claims mapping feature.
InboundClaimTypeMap = new Dictionary<string, string>()
};

options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
});

授权启动:

.AddServer(options =>
{
// Register the ASP.NET Core MVC services used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.UseMvc();

// Enable the authorization, logout, token and userinfo endpoints.
options.EnableAuthorizationEndpoint("/connect/authorize")
.EnableLogoutEndpoint("/connect/logout")
.EnableTokenEndpoint("/connect/token")
.EnableUserinfoEndpoint("/api/userinfo");

options
.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();

// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(
OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles,
OpenIddictConstants.Scopes.OfflineAccess);

// When request caching is enabled, authorization and logout requests
// are stored in the distributed cache by OpenIddict and the user agent
// is redirected to the same page with a single parameter (request_id).
// This allows flowing large OpenID Connect requests even when using
// an external authentication provider like Google, Facebook or Twitter.
options.EnableRequestCaching();

// During development, you can disable the HTTPS requirement.
if (env.IsDevelopment())
{
options.DisableHttpsRequirement();
options.AddEphemeralSigningKey(); // TODO: In production, use a X.509 certificate ?
}

options.SetAccessTokenLifetime(TimeSpan.FromMinutes(openIdConnectConfig.AccessTokenLifetimeInMinutes));
options.SetRefreshTokenLifetime(TimeSpan.FromHours(12));
})
.AddValidation();

描述符:

var descriptor = new OpenIddictApplicationDescriptor{
ClientId = config.Id,
ClientSecret = config.Secret,
DisplayName = config.DisplayName,
PostLogoutRedirectUris = { new Uri($"{config.ClientOrigin}/signout-callback-oidc") },
RedirectUris = { new Uri($"{config.ClientOrigin}/signin-oidc") },
Permissions =
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
OpenIddictConstants.Permissions.Scopes.Email,
OpenIddictConstants.Permissions.Scopes.Profile,
OpenIddictConstants.Permissions.Scopes.Roles
}};

token 端点:

if (request.IsRefreshTokenGrantType()){
// Retrieve the claims principal stored in the refresh token.
var info = await HttpContext.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);

// Retrieve the user profile corresponding to the refresh token.
// Note: if you want to automatically invalidate the refresh token
// when the user password/roles change, use the following line instead:
// var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
var user = await _userManager.GetUserAsync(info.Principal);
if (user == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The refresh token is no longer valid."
});
}

// Ensure the user is still allowed to sign in.
if (!await _signInManager.CanSignInAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The user is no longer allowed to sign in."
});
}

// Create a new authentication ticket, but reuse the properties stored
// in the refresh token, including the scopes originally granted.
var ticket = await CreateTicketAsync(request, user, info.Properties);
ticket.SetScopes(OpenIdConnectConstants.Scopes.OfflineAccess);

return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);}

最佳答案

尝试使用您的访问 token 调用 protected 资源是可以接受的,即使它可能已过期、无效等。如果 protected 资源拒绝 token ,您可以尝试通过发送 POST 来获取新的访问 token 带有刷新 token 的/token 端点。这是一些 JS,但这个概念仍然适用。

var refreshAccessToken = function(req, res) {
var form_data = qs.stringify(
{
grant_type: 'refresh_token',
refresh_token: refresh_token
});
var headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + encodeClientCredentials(client.client_id,
client.client_secret)
};
console.log('Refreshing token %s', refresh_token);
var tokRes = request('POST', authServer.tokenEndpoint, {
body: form_data,
headers: headers
});
if (tokRes.statusCode >= 200 && tokRes.statusCode < 300) {
var body = JSON.parse(tokRes.getBody());

access_token = body.access_token;
console.log('Got access token: %s', access_token);
if (body.refresh_token) {
refresh_token = body.refresh_token;
console.log('Got refresh token: %s', refresh_token);
}
scope = body.scope;
console.log('Got scope: %s', scope);

// try again
res.redirect('/fetch_resource');
return;
} else {
console.log('No refresh token, asking the user to get a new access token');
// tell the user to get a new access token
refresh_token = null;
res.render('error', {error: 'Unable to refresh token.'});
return;
}
};

关于openid-connect - OpenIdDict(代码流)——处理访问 token 过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55282896/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com