未包含在 JWT 中且未发送到 Web Api 的 IdentityServer4 用户声明

Posted

技术标签:

【中文标题】未包含在 JWT 中且未发送到 Web Api 的 IdentityServer4 用户声明【英文标题】:Claims for IdentityServer4 user not included in JWT and not sent to Web Api 【发布时间】:2017-05-30 14:18:08 【问题描述】:

按照官方 IdentityServer4 文档,我达到了拥有 MVC 客户端应用程序、IdentityServer4 和 Web Api(正在运行的资源服务器)的地步。 IS4 主页显示用户的所有声明,当使用访问令牌调用 api 时,我们再次得到用户的所有声明。

here 提供了示例代码,尽管它可能不是必需的,我只是遗漏了一些明显的东西。

无论如何,为了简单起见,我们不要从数据库中获取声明,而只是分配一个随机硬编码的声明:

public class ProfileService : IProfileService

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    
        context.IssuedClaims.Add(new System.Security.Claims.Claim("role", "admin"));
        return Task.FromResult(0);
    
    ...

我在启动文件中注册了自定义配置文件服务,现在当我登录 IS4 时,我看到了附加声明。

但是,当调用 web api(资源服务器)时,这个额外的声明不包含在 JWT 中。 api调用代码:

    public async Task<IActionResult> CallApiUsingUserAccessToken()
    
        var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

        var client = new HttpClient();
        client.SetBearerToken(accessToken);
        var content = await client.GetStringAsync("http://localhost:5001/identity");

        ViewBag.Json = JArray.Parse(content).ToString();
        return View("json");
    

(所有 api 所做的只是返回 User.Claims 列表)。我添加的声明不在其中,当我调试代码并选择访问令牌字符串并在 jwt.io 上对其进行解码时,再次没有这样的声明。

问题是:我错过了什么? HttpContext.Authentication.GetTokenAsync 对我的用例不利吗?如果是,我应该使用什么替代品?

编辑:这里是 OpenId 连接选项(在 MVC 客户端上):

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = "http://localhost:5000",
            RequireHttpsMetadata = false,

            ClientId = "mvc",
            ClientSecret = "secret",

            ResponseType = "code id_token",
            Scope =  "api1", "offline_access" ,

            GetClaimsFromUserInfoEndpoint = true,
            SaveTokens = true
        );

【问题讨论】:

如果您正在使用请提供OpenIdConnectOptions 我不确定我是否理解正确,但仅仅因为您在 Web 方法中在服务器端添加了新声明,并不意味着您重新颁发令牌以实际包含此新声明。尝试任何其他方法,例如删除所有声明,效果应该是一样的。除非您发布新令牌,否则您在服务器上对身份所做的更改是暂时的,并且仅在此类特定请求期间才会持续。类似于从服务器的 cookie 集合中删除 cookie,但不发送新的 set-cookie 以在客户端实际删除它。 【参考方案1】:

我猜原因是您没有为您的 API 分配任何声明。这就是我们根本不调用配置文件服务的原因。

这是一个常见问题,而且有点不一致,因为我们总是调用配置文件服务来获取身份令牌。

我们在 1.0.2 中改变了这种行为

https://github.com/IdentityServer/IdentityServer4/releases/tag/1.0.2

请再试一次,看看这是否会给您带来预期的结果。

【讨论】:

确实如此,非常感谢!我想这从来都不是错误,但是新的 IS4 版本省去了很多麻烦,因为 openId connect 的大多数方面确实不直观。 如果没有在 AspNetUserClaims 中明确添加,如何添加电子邮件和用户名声明? @leastprivilege 澄清一下,您是说通过此修改,IProfileService 设置的声明现在总是添加到身份令牌访问令牌?而旧的行为只是将它们附加到身份令牌?这似乎是我所看到的,从 1.0.0 移动到 1.1.1。 从阅读the code 的那个提交,看起来IProfileService 确实为每个令牌类型查询。

以上是关于未包含在 JWT 中且未发送到 Web Api 的 IdentityServer4 用户声明的主要内容,如果未能解决你的问题,请参考以下文章

jQuery Web Socket 未连接且未发送

MERN mongoDB 集合未更新且未发送响应

MERN mongoDB 集合未更新且未发送响应

Axios:网络错误且未发送请求

TextboxFor 元素和 CheckboxFor 元素为 null 且未发送到 POST

如何跨不同 API 对 JSON Web 令牌 (JWT) 进行身份验证?