身份服务器不返回刷新令牌
Identity Server not returning refresh token
我正在尝试设置 Thinktecture 的 Identity Server 3,但在交换授权代码时(或在使用 ResourceOwner 流程时,我似乎无法将其设置为 return 刷新令牌,但我我将专注于授权代码,因为它现在对我来说更重要)。我取回了访问令牌并可以使用它们进行身份验证,但它似乎甚至没有生成我期望取回的刷新令牌。我需要做些什么才能让 Identity Server return 刷新令牌?
我查看了文档,但没有发现任何我设置错误的地方,refresh tokens 他们页面上唯一我没有做的事情就是明确要求"offline_access" 将用户发送到那里进行身份验证时的范围,因为每当我尝试时都会收到 "invalid scope" 错误。因此,我采用 Thinktecture 的 "Request the offline_access scope (via code or resource owner flow)" 措辞来表示 offline_access 范围是根据您使用的流程自动请求的。
我一直在尽力遵循他们的示例应用程序(以及来自 Katana Project 的现有 Owin 中间件的源代码),我的设置如下:
- 我使用他们的客户端 class 创建了一个客户端,手动指定以下内容:
var client = new Client()
{
ClientId = "SomeId",
ClientName = "Client with Authentication Code Flow",
RequireConsent = false, //Setting this to true didn't help
Flow = Flows.AuthorizationCode,
ClientSecrets = new List() {
new ClientSecret("secret")
},
RedirectUris = new List()
{
"localhost:/specific-redirect-path"
}
};
- 我正在调用授权端点,如下所示:
var authorizationEndpoint =
AuthorizationEndpointBase +
"?client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&scope=Default" +
"&response_type=code" +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
"&state=" + Uri.EscapeDataString(state);
Response.Redirect(authorizationEndpoint);
其中 "Default" 是我创建的范围。
- 在我的回调中,我按如下方式调用令牌端点:
IReadableStringCollection query = Request.Query;
string code = getValueFromQueryString("code", query);
var tokenRequestParameters = new List>()
{
new KeyValuePair("client_id", Options.ClientId),
new KeyValuePair("redirect_uri", GenerateRedirectUri()),
new KeyValuePair("client_secret", Options.ClientSecret),
new KeyValuePair("code", code),
new KeyValuePair("grant_type", "authorization_code"),
};
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
HttpResponseMessage response = await _httpClient.PostAsync(TokenEndpoint, requestContent, Request.CallCancelled);
response.EnsureSuccessStatusCode();
string oauthTokenResponse = await response.Content.ReadAsStringAsync();
当我调用令牌端点时,我在 Identity Server 上的登录显示如下(在验证授权码之后):
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Validation.TokenRequestValidator]: 7/13/2015 1:44:07 PM +00:00 -- Token request validation success
{
"ClientId": "SomeId",
"ClientName": "Client with Authentication Code Flow",
"GrantType": "authorization_code",
"AuthorizationCode": "f8f795e649044067ebd96a341c5af8c3"
}
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.ResponseHandling.TokenResponseGenerator]: 7/13/2015 1:44:07 PM +00:00 -- Creating token response
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.ResponseHandling.TokenResponseGenerator]: 7/13/2015 1:44:07 PM +00:00 -- Processing authorization code request
Debug: [Thinktecture.IdentityServer.Core.Services.Default.DefaultTokenService]: 7/13/2015 1:44:07 PM +00:00 -- Creating access token
Debug: [Thinktecture.IdentityServer.Core.Services.Default.DefaultTokenService]: 7/13/2015 1:44:07 PM +00:00 -- Creating reference access token
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Endpoints.TokenEndpointController]: 7/13/2015 1:44:07 PM +00:00 -- End token request
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Results.TokenResult]: 7/13/2015 1:44:07 PM +00:00 -- Returning token response.
我不确定还有什么是相关的,所以我会根据需要提供更多信息。
您必须在请求中明确要求 'offline_access'。用 space 分隔您请求的其他范围。 (在我下面的示例中,我将 'Default' 替换为 'MyApi' 以明确我们正在讨论您的应用程序定义的范围。)
&scope=MyApi offline_access
但是,您还必须授予该客户端获取刷新令牌的权利,这不仅仅取决于您选择的流程:
var client = new Client()
{
... //All the stuff you were doing before
ScopeRestrictions = new List<string>
{
"MyApi",
StandardScopes.OfflineAccess.Name, //"offline_access" -for refresh tokens
//Other commonly requested scopes:
//StandardScopes.OpenId.Name, //"openid"
//StandardScopes.Email.Name, //"email"
},
}
您可能还需要将 'offline_access' 添加到您的范围存储中。范围存储是 Identity Server 知道的范围列表。你的问题没有提到你的范围商店是如何在你的项目中设置的,所以你可能已经有了它。但是,如果以上方法不能立即为您工作,您可能需要在您正在使用的示例中寻找类似这样的代码并添加 OfflineAccess。
var scopeStore = new InMemoryScopeStore(new Scope[]{
StandardScopes.OpenId,
StandardScopes.Profile,
StandardScopes.Email,
StandardScopes.OfflineAccess, //<--- ensure this is here to allow refresh tokens
new Scope{
Enabled = true,
Name = "MyApi"
},
}
在发送令牌请求时在范围内添加 offline_access 值
new Client
{
ClientId = "ro.angular",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Address,
"api1",
IdentityServerConstants.StandardScopes.OfflineAccess
},
AllowOfflineAccess = true,
RefreshTokenUsage = TokenUsage.ReUse,
RefreshTokenExpiration = TokenExpiration.Sliding
}
我正在尝试设置 Thinktecture 的 Identity Server 3,但在交换授权代码时(或在使用 ResourceOwner 流程时,我似乎无法将其设置为 return 刷新令牌,但我我将专注于授权代码,因为它现在对我来说更重要)。我取回了访问令牌并可以使用它们进行身份验证,但它似乎甚至没有生成我期望取回的刷新令牌。我需要做些什么才能让 Identity Server return 刷新令牌?
我查看了文档,但没有发现任何我设置错误的地方,refresh tokens 他们页面上唯一我没有做的事情就是明确要求"offline_access" 将用户发送到那里进行身份验证时的范围,因为每当我尝试时都会收到 "invalid scope" 错误。因此,我采用 Thinktecture 的 "Request the offline_access scope (via code or resource owner flow)" 措辞来表示 offline_access 范围是根据您使用的流程自动请求的。
我一直在尽力遵循他们的示例应用程序(以及来自 Katana Project 的现有 Owin 中间件的源代码),我的设置如下:
- 我使用他们的客户端 class 创建了一个客户端,手动指定以下内容:
var client = new Client() { ClientId = "SomeId", ClientName = "Client with Authentication Code Flow", RequireConsent = false, //Setting this to true didn't help Flow = Flows.AuthorizationCode, ClientSecrets = new List() { new ClientSecret("secret") }, RedirectUris = new List() { "localhost:/specific-redirect-path" } };
- 我正在调用授权端点,如下所示:
var authorizationEndpoint = AuthorizationEndpointBase + "?client_id=" + Uri.EscapeDataString(Options.ClientId) + "&scope=Default" + "&response_type=code" + "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + "&state=" + Uri.EscapeDataString(state); Response.Redirect(authorizationEndpoint);
其中 "Default" 是我创建的范围。 - 在我的回调中,我按如下方式调用令牌端点:
IReadableStringCollection query = Request.Query; string code = getValueFromQueryString("code", query); var tokenRequestParameters = new List>() { new KeyValuePair("client_id", Options.ClientId), new KeyValuePair("redirect_uri", GenerateRedirectUri()), new KeyValuePair("client_secret", Options.ClientSecret), new KeyValuePair("code", code), new KeyValuePair("grant_type", "authorization_code"), }; var requestContent = new FormUrlEncodedContent(tokenRequestParameters); HttpResponseMessage response = await _httpClient.PostAsync(TokenEndpoint, requestContent, Request.CallCancelled); response.EnsureSuccessStatusCode(); string oauthTokenResponse = await response.Content.ReadAsStringAsync();
当我调用令牌端点时,我在 Identity Server 上的登录显示如下(在验证授权码之后):
iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Validation.TokenRequestValidator]: 7/13/2015 1:44:07 PM +00:00 -- Token request validation success { "ClientId": "SomeId", "ClientName": "Client with Authentication Code Flow", "GrantType": "authorization_code", "AuthorizationCode": "f8f795e649044067ebd96a341c5af8c3" } iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.ResponseHandling.TokenResponseGenerator]: 7/13/2015 1:44:07 PM +00:00 -- Creating token response iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.ResponseHandling.TokenResponseGenerator]: 7/13/2015 1:44:07 PM +00:00 -- Processing authorization code request Debug: [Thinktecture.IdentityServer.Core.Services.Default.DefaultTokenService]: 7/13/2015 1:44:07 PM +00:00 -- Creating access token Debug: [Thinktecture.IdentityServer.Core.Services.Default.DefaultTokenService]: 7/13/2015 1:44:07 PM +00:00 -- Creating reference access token iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Endpoints.TokenEndpointController]: 7/13/2015 1:44:07 PM +00:00 -- End token request iisexpress.exe Information: 0 : [Thinktecture.IdentityServer.Core.Results.TokenResult]: 7/13/2015 1:44:07 PM +00:00 -- Returning token response.
我不确定还有什么是相关的,所以我会根据需要提供更多信息。
您必须在请求中明确要求 'offline_access'。用 space 分隔您请求的其他范围。 (在我下面的示例中,我将 'Default' 替换为 'MyApi' 以明确我们正在讨论您的应用程序定义的范围。)
&scope=MyApi offline_access
但是,您还必须授予该客户端获取刷新令牌的权利,这不仅仅取决于您选择的流程:
var client = new Client()
{
... //All the stuff you were doing before
ScopeRestrictions = new List<string>
{
"MyApi",
StandardScopes.OfflineAccess.Name, //"offline_access" -for refresh tokens
//Other commonly requested scopes:
//StandardScopes.OpenId.Name, //"openid"
//StandardScopes.Email.Name, //"email"
},
}
您可能还需要将 'offline_access' 添加到您的范围存储中。范围存储是 Identity Server 知道的范围列表。你的问题没有提到你的范围商店是如何在你的项目中设置的,所以你可能已经有了它。但是,如果以上方法不能立即为您工作,您可能需要在您正在使用的示例中寻找类似这样的代码并添加 OfflineAccess。
var scopeStore = new InMemoryScopeStore(new Scope[]{
StandardScopes.OpenId,
StandardScopes.Profile,
StandardScopes.Email,
StandardScopes.OfflineAccess, //<--- ensure this is here to allow refresh tokens
new Scope{
Enabled = true,
Name = "MyApi"
},
}
在发送令牌请求时在范围内添加 offline_access 值
new Client
{
ClientId = "ro.angular",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Address,
"api1",
IdentityServerConstants.StandardScopes.OfflineAccess
},
AllowOfflineAccess = true,
RefreshTokenUsage = TokenUsage.ReUse,
RefreshTokenExpiration = TokenExpiration.Sliding
}