首页 新闻 会员 周边

Identity Server 4: 请求 token 时没有返回 refresh token

0
悬赏园豆:40 [已解决问题] 解决于 2023-07-26 15:34

通过下面的 C# 代码请求 token 时只返回了 access token,没有返回 refresh token

var httpClient = _httpClientFactory.CreateClient();

var parameters = new FormUrlEncodedContent(new Dictionary<string, string>
{
    ["client_id"] = _apiOptions.ClientId,
    ["client_secret"] = _apiOptions.ClientSecret,
    ["grant_type"] = "authorization_code",
    ["code"] = _memoryCache.Get<string>("code"),
    ["redirect_uri"] = _apiOptions.RedirectUri
});

var response = await httpClient.PostAsync($"{_apiOptions.OauthUrl}/connect/token", parameters);

以前是正常的,请问如何解决这个问题?

dudu的主页 dudu | 高人七级 | 园豆:30948
提问于:2023-07-26 12:47
< >
分享
最佳答案
0

是请求 /connect/authoriz 时的 scope 参数中少了 offline_access 引起的

排查过程:

  • 查看 IdentityServer4 的源码 TokenResponseGenerator.cs#L362 得知是否返回 refresh token 取决于请求的 scope 参数中是否包含 offline_access
createRefreshToken = request.AuthorizationCode.RequestedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess);
  • 开始尝试在 /connect/token 的请求参数中加上 scope=offline_access,问题依旧
  • 后来发现应该在 /connect/authorizescope 请求参数中增加 offline_access
public IActionResult Authorize()
{
    var url = QueryHelpers.AddQueryString(
        $"{_apiOptions.OauthUrl}/connect/authorize",
        new Dictionary<string, string>
        {
            ["client_id"] = _apiOptions.ClientId,
            ["scope"] = "openid profile CnBlogsApi offline_access",
            ["response_type"] = "code id_token",
            ["redirect_uri"] = _apiOptions.RedirectUri,
            ["state"] = "cnblogs open api",
            ["nonce"] = Guid.NewGuid().ToString(),
            ["response_mode"] = "form_post"
        });

    return Redirect(url);
}
dudu | 高人七级 |园豆:30948 | 2023-07-26 15:32
其他回答(1)
0

以下是一个示例代码,包括调用 PostAsync 方法并处理返回的响应的代码:

var httpClient = _httpClientFactory.CreateClient();

var parameters = new FormUrlEncodedContent(new Dictionary<string, string>
{
    ["client_id"] = _apiOptions.ClientId,
    ["client_secret"] = _apiOptions.ClientSecret,
    ["grant_type"] = "authorization_code",
    ["code"] = _memoryCache.Get<string>("code"),
    ["redirect_uri"] = _apiOptions.RedirectUri
});

var response = await httpClient.PostAsync($"{_apiOptions.OauthUrl}/connect/token", parameters);

if (response.IsSuccessStatusCode)
{
    var responseContent = await response.Content.ReadAsStringAsync();
    var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
    
    // 处理返回的令牌响应
    var accessToken = tokenResponse.AccessToken;
    var refreshToken = tokenResponse.RefreshToken;
    // 其他处理逻辑
}
else
{
    // 处理请求失败的情况
    var errorResponse = await response.Content.ReadAsStringAsync();
    // 其他错误处理逻辑
}

确保你检查了 response 对象的内容,看看是否包含 refresh_token。通常,返回的令牌响应是一个 JSON 对象,你可以通过 response.Content.ReadAsStringAsync() 将其转换为字符串或使用相应的 JSON 解析方法转换为对象,并查看其中的 refresh_token 字段。

如果 refresh_token 字段确实不存在,则可能是以下原因之一:

你的 Identity Server 4 配置不包括 refresh_token 预定义的授权类型。你需要确保在 Identity Server 4 配置中包含 refresh_token 的授权类型。

当你的授权码 code 被使用一次之后,它将会失效。这意味着你只能使用它一次来请求令牌。确保你并没有多次使用同一个 code 值来请求令牌。

收获园豆:40
lanedm | 园豆:2381 (老鸟四级) | 2023-07-26 14:43
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册