使用客户端凭证流持久化令牌的最佳实践
Best practice for persisting tokens using Client Credentials flow
我有一个允许匿名用户的 ASP.NET 核心 MVC 应用程序。此应用程序正在调用受 Identity Server 4 保护的 ASP.NET Web API。我在 Identity Server 中创建了一个描述 MVC 应用程序(客户端)的客户端,并授予它访问 api范围如下:
new Client
{
ClientId = "my-mvc-client-app",
AllowedGrantTypes = GrantTypes.ClientCredentials,
RequireConsent = false,
ClientSecrets = new List<Secret> { new Secret("this-is-my-secret".Sha256()) },
AllowedScopes = new List<string>
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
StandardScopes.OfflineAccess.Name,
"my-protected-api"
},
RedirectUris = new List<string>
{
"http://localhost:5009/signin-oidc",
}
}
在我的 MVC 应用程序中,我使用 TokenClient
获取令牌,我可以在向受保护的 API 发出请求时使用该令牌,如下所示:
var disco = await DiscoveryClient.GetAsync("http://localhost:5010");
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("hrmts-test-candidate-api-scope");
这工作正常,但我在每次请求时都从 Identity Server 请求新令牌,这可能不是一个好主意。
处理令牌的最佳做法是什么?我如何将它们保存在客户端(MVC 应用程序)上以及如何处理刷新令牌以确保客户端在必要时获得新令牌?
您需要将该客户端包装在某种托管服务中(作为单例),以便您可以在任何需要的地方使用它。我们有一个令牌组件,用于遵循以下流程的服务器到服务器通信:
public class ServerTokenComponent
{
private TokenResponse Token { get; set; }
private DateTime ExpiryTime { get; set; }
public async Task<TokenResponse> GetToken()
{
//use token if it exists and is still fresh
if (Token != null && ExpiryTime > DateTime.UtcNow)
{
return Token;
}
//else get a new token
var client = new TokenClient("myidpauthority.com","theclientId","thesecret")
var scopes = "for bar baz";
var tokenResponse = await client.RequestClientCredentialsAsync(scopes);
if (tokenResponse.IsError || tokenResponse.IsHttpError)
{
throw new SecurityTokenException("Could not retrieve token.");
}
//set Token to the new token and set the expiry time to the new expiry time
Token = tokenResponse;
ExpiryTime = DateTime.UtcNow.AddSeconds(Token.ExpiresIn);
//return fresh token
return Token;
}
}
换句话说 - 您需要以某种方式缓存该令牌。当您请求令牌时,您会在响应中得到一个 ExpiresIn - 这将告诉您令牌的有效期。
另一种选择是等到 API returns 401 - 然后请求一个新令牌。
刷新令牌不用于客户端凭据流。
我有一个允许匿名用户的 ASP.NET 核心 MVC 应用程序。此应用程序正在调用受 Identity Server 4 保护的 ASP.NET Web API。我在 Identity Server 中创建了一个描述 MVC 应用程序(客户端)的客户端,并授予它访问 api范围如下:
new Client
{
ClientId = "my-mvc-client-app",
AllowedGrantTypes = GrantTypes.ClientCredentials,
RequireConsent = false,
ClientSecrets = new List<Secret> { new Secret("this-is-my-secret".Sha256()) },
AllowedScopes = new List<string>
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
StandardScopes.OfflineAccess.Name,
"my-protected-api"
},
RedirectUris = new List<string>
{
"http://localhost:5009/signin-oidc",
}
}
在我的 MVC 应用程序中,我使用 TokenClient
获取令牌,我可以在向受保护的 API 发出请求时使用该令牌,如下所示:
var disco = await DiscoveryClient.GetAsync("http://localhost:5010");
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("hrmts-test-candidate-api-scope");
这工作正常,但我在每次请求时都从 Identity Server 请求新令牌,这可能不是一个好主意。
处理令牌的最佳做法是什么?我如何将它们保存在客户端(MVC 应用程序)上以及如何处理刷新令牌以确保客户端在必要时获得新令牌?
您需要将该客户端包装在某种托管服务中(作为单例),以便您可以在任何需要的地方使用它。我们有一个令牌组件,用于遵循以下流程的服务器到服务器通信:
public class ServerTokenComponent
{
private TokenResponse Token { get; set; }
private DateTime ExpiryTime { get; set; }
public async Task<TokenResponse> GetToken()
{
//use token if it exists and is still fresh
if (Token != null && ExpiryTime > DateTime.UtcNow)
{
return Token;
}
//else get a new token
var client = new TokenClient("myidpauthority.com","theclientId","thesecret")
var scopes = "for bar baz";
var tokenResponse = await client.RequestClientCredentialsAsync(scopes);
if (tokenResponse.IsError || tokenResponse.IsHttpError)
{
throw new SecurityTokenException("Could not retrieve token.");
}
//set Token to the new token and set the expiry time to the new expiry time
Token = tokenResponse;
ExpiryTime = DateTime.UtcNow.AddSeconds(Token.ExpiresIn);
//return fresh token
return Token;
}
}
换句话说 - 您需要以某种方式缓存该令牌。当您请求令牌时,您会在响应中得到一个 ExpiresIn - 这将告诉您令牌的有效期。
另一种选择是等到 API returns 401 - 然后请求一个新令牌。
刷新令牌不用于客户端凭据流。