如何使 IdentityServer 将用户身份添加到访问令牌?

Posted

技术标签:

【中文标题】如何使 IdentityServer 将用户身份添加到访问令牌?【英文标题】:How to make IdentityServer to add user identity to the access token? 【发布时间】:2016-07-31 02:02:30 【问题描述】:

简短:我的客户端从 IdentityServer 示例服务器检索访问令牌,然后将其传递给我的 WebApi。在我的控制器中, this.HttpContext.User.GetUserId() 返回 null (尽管用户有其他声明)。我怀疑访问令牌中没有名称身份声明。如何让 IdentityServer 包含它?

到目前为止我已经尝试过:

从混合流切换到隐式流(随机尝试)

在我添加的 IdSvrHost 范围定义中

Claims = new ScopeClaim(ClaimTypes.NameIdentifier, alwaysInclude: true)

在我添加的 IdSvrHost 客户端定义中

Claims = new Claim(ClaimTypes.NameIdentifier, "42")

(也是随机尝试)

我还尝试了范围定义中的其他范围,但都没有出现。看起来,nameidentity 通常包含在身份令牌中,但是对于我知道的大多数公共 API,您不会向服务器提供身份令牌。

更多详情: IdSrvHost 和 Api 位于不同的主机上。 控制器具有[授权]。事实上,我可以看到其他的说法。 Api 配置有

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

app.UseIdentityServerAuthentication(options => 
    options.Authority = "http://localhost:22530/";

    // TODO: how to use multiple optional scopes?
    options.ScopeName = "borrow.slave";
    options.AdditionalScopes = new[]  "borrow.receiver", "borrow.manager" ;

    options.AutomaticAuthenticate = true;
    options.AutomaticChallenge = true;
);

范围:

public static Scope Slave  get;  = new Scope 
    Name = "borrow.slave",
    DisplayName = "List assigned tasks",
    Type = ScopeType.Resource,

    Claims = 
        new ScopeClaim(ClaimTypes.NameIdentifier, alwaysInclude: true),
    ,
;

和客户:

new Client 
    ClientId = "borrow_node",
    ClientName = "Borrow Node",

    Flow = Flows.Implicit,

    RedirectUris = new List<string>
    
        "borrow_node:redirect-target",
    ,

    Claims =  new Claim(ClaimTypes.NameIdentifier, "42") ,

    AllowedScopes = 
        StandardScopes.OpenId.Name,
        //StandardScopes.OfflineAccess.Name,
        BorrowScopes.Slave.Name,
    ,

授权 URI:

request.CreateAuthorizeUrl(
            clientId: "borrow_node",
            responseType: "token",
            scope: "borrow.slave",
            redirectUri: "borrow_node:redirect-target",
            state: state,
            nonce: nonce);

我也试过了

request.CreateAuthorizeUrl(
            clientId: "borrow_node",
            responseType: "id_token token",
            scope: "openid borrow.slave",
            redirectUri: "borrow_node:redirect-target",
            state: state,
            nonce: nonce);

【问题讨论】:

如果您不确定 access_token 中的内容,请将其复制并粘贴到 jwt.io 并查看声明。 这是我在 access_token 中得到的: "iss": "localhost:22530", "aud": "localhost:22530/resources", "exp": 1460323801, "nbf": 1460320201, "client_id “:“borrow_node”,“范围”:“borrow.slave”,“sub”:“88421113”,“auth_time”:1460320200,“idp”:“idsvr” - 没有名称身份声明 顺便说一句,我不希望 nameidentity 为“42”,这只是试图看看这是否会改变任何东西。 已检查 IdentityServer 源代码(未调试):看来,这一行会过滤掉 nameidentity:var claim = FilterProtocolClaims(context.IssuedClaims); 行在 DefaultClaimsProvider.cs 中。看起来这是设计使然,access_token 不包括 IdentityServer 中的用户身份。如果是这样,我是否必须将 id_token 和 access_token 都传递给 API 端点? Bearer怎么能做到这一点? 【参考方案1】:

万岁,当我偶然发现此页面时,我找到了答案:https://github.com/IdentityServer/IdentityServer3.Samples/issues/173

显然,用户身份是在访问令牌中的“sub”声明中传递的。因为我一味抄袭API示例,所以包含了它的配置

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

这基本上阻止了我的 API 将“子”声明映射到名称标识符。删除此行后,认证控制器的 HttpContext.User.GetUserId() 正确返回用户 ID。

【讨论】:

以上是关于如何使 IdentityServer 将用户身份添加到访问令牌?的主要内容,如果未能解决你的问题,请参考以下文章

IdentityServer4专题之二:OpenID介绍

两个identityserver怎么sso

IdentityServer4- 使用OpenID Connect添加用户身份验证(implicit)

如何将 IdentityServer4 设置为外部身份提供者

IdentityServer4如何创建身份令牌?

是否可以将 IdentityServer4 中的用户注销为其他用户?