10

我有一个允许匿名用户的 ASP.NET Core 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 应用程序)上,如何处理刷新令牌以确保客户端在必要时获得新令牌?

4

2 回答 2

12

您需要将该客户端包装在某种托管服务中(作为单例),以便您可以在需要的任何地方使用它。我们有一个令牌组件,用于遵循此流程的服务器到服务器通信:

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;
    }
}
于 2016-09-26T13:58:18.100 回答
4

换句话说 - 您需要以某种方式缓存该令牌。当您请求令牌时,您会在响应中得到一个 ExpiresIn - 这将告诉您令牌的有效期。

另一种选择是等到 API 返回 401 - 然后请求新令牌。

刷新令牌不与客户端凭据流一起使用。

于 2016-09-26T18:13:51.150 回答