如何在包含访问令牌时从客户端应用中的IdentityServer获取用户ID?

时间:2017-03-29 20:39:03

标签: c# identityserver3 oidc

我已经实现了基于IdentityServer3的身份验证服务和一个简单的MVC客户端应用程序以及由身份验证服务保护的Shopper API。我已经实现了IdentityServer自定义UserService,以便身份验证服务对我们现有的用户数据存储进行身份验证。 My Shopper API需要Shopper Get请求中的用户ID。目前,来自身份验证服务的响应包括身份令牌和访问令牌,但没有用户ID。我尝试在自定义UserService.AuthenticateLocalAsync方法的AuthenticationResult中添加user_id声明,但我在客户端应用程序代码中没有看到它。 UserService.AuthenticateLocalAsync如下所示:

try
{
    var user = new shopper(_dbConnLib, context.UserName, context.Password);
    var claims = new List<Claim> { new Claim("user_id", user.shopperid) };
    context.AuthenticateResult = new AuthenticateResult(user.shopperid, user.MemberDetail.billToAddress.FirstName, claims);
}
catch(shopperInitFromException ex)
{
    context.AuthenticateResult = null;  // Indicates username/password failure
}
return Task.FromResult(0);

我的客户端应用程序SecurityTokenValidated处理程序如下所示:

SecurityTokenValidated = async n =>
{
    var nid = new ClaimsIdentity(
        n.AuthenticationTicket.Identity.AuthenticationType,
        Constants.ClaimTypes.GivenName,
        Constants.ClaimTypes.Role);

    var userInfoClient = new UserInfoClient(
        new Uri(n.Options.Authority + "/connect/userinfo").ToString());

    var userInfo = await userInfoClient.GetAsync(n.ProtocolMessage.AccessToken);
    userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Type, ui.Value)));

    nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

    nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));

    //nid.AddClaim(new Claim("user_id", n.ProtocolMessage.UserId));

    nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));

    n.AuthenticationTicket = new AuthenticationTicket(
        nid,
        n.AuthenticationTicket.Properties);
}

如果我在调试器中单步调试,userInfo.Claims的计数总是为0.如何使用用户的唯一标识符取回声明?或者我可以从身份或访问令牌中获取它吗?或者我应该将令牌传递给Shopper API并让它从令牌中确定ID?

1 个答案:

答案 0 :(得分:1)

我想我可能有答案。到目前为止,据我所知,我在AuthenticateLocalAsync的重写中包含在AuthenticateResult构造函数中的声明似乎无处可去。但是我在我的覆盖GetProfileDataAsync中包含的声明出现在令牌中。我的GetProfileDataAsync代码似乎正确设置了声明,如下所示:

public override Task GetProfileDataAsync(ProfileDataRequestContext context)
{
    var user = new shopper(_dbConnLib, context.Subject.FindFirst("sub").Value);
    var claims = new List<Claim> { new Claim("sub", user.shopperid), new Claim("acr_level", "level 0"), new Claim("amr", "anonymous") };
    context.IssuedClaims = claims;
    return Task.FromResult(0);
}

我的AuthenticateLocalAsync代码在AuthenticateResult中设置我从未在客户端应用程序代码中看到的声明,如下所示:

public override Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
    // TODO: Handle AddshopperToBasketException in UserService.AuthenticateLocalAsync
    try
    {
        var user = new shopper(_dbConnLib, context.UserName, context.Password);
        var claims = new List<Claim> { new Claim("acr_level", "level 0"), new Claim("amr", "anonymous") };
        context.AuthenticateResult = new AuthenticateResult(user.shopperid, user.MemberDetail.billToAddress.FirstName, claims);
    }
    catch(shopperInitFromException ex)
    {
        context.AuthenticateResult = null;  // Indicates username/password failure
    }
    return Task.FromResult(0);
}