C# 当包含访问令牌时,如何从客户端应用程序中的IdentityServer获取用户id?

C# 当包含访问令牌时,如何从客户端应用程序中的IdentityServer获取用户id?,c#,identityserver3,openid-connect,C#,Identityserver3,Openid Connect,我已经实现了一个基于IdentityServer3的身份验证服务,一个简单的MVC客户端应用程序和一个由身份验证服务保护的购物者API。我已经实现了一个IdentityServer自定义用户服务,以便身份验证服务根据现有的用户数据存储进行身份验证。我的购物者API要求购物者Get请求中有一个用户ID。当前,来自身份验证服务的响应包括身份令牌和访问令牌,但没有用户id。我尝试从我的自定义UserService.AuthenticateLocalAsync方法在AuthenticationResul

我已经实现了一个基于IdentityServer3的身份验证服务,一个简单的MVC客户端应用程序和一个由身份验证服务保护的购物者API。我已经实现了一个IdentityServer自定义用户服务,以便身份验证服务根据现有的用户数据存储进行身份验证。我的购物者API要求购物者Get请求中有一个用户ID。当前,来自身份验证服务的响应包括身份令牌和访问令牌,但没有用户id。我尝试从我的自定义UserService.AuthenticateLocalAsync方法在AuthenticationResult中添加用户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 = 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);
}
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);
}
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);
}

如果我在调试器中单步执行,userInfo.Claims的计数始终为0。如何使用用户的唯一标识符取回索赔?或者我可以从身份或访问令牌获得它?或者我应该将令牌传递给Shopper API,让它根据令牌确定id吗

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

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 = 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);
}
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);
}
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);
}
公共覆盖任务GetProfileDataAsync(ProfileDataRequestContext上下文)
{
var user=新购物者(_dbConnLib,context.Subject.FindFirst(“sub”).Value);
var索赔=新列表{新索赔(“sub”,user.shopperid),新索赔(“acr_级别”,“0级”),新索赔(“amr”,“匿名”)};
context.IssuedClaims=索赔;
返回Task.FromResult(0);
}
我的AuthenticateLocalAsync代码在AuthenticateResult中设置声明,而我在客户端应用程序代码中从未见过该声明,它如下所示:

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 = 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);
}
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);
}
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);
}
public覆盖任务AuthenticateLocalAsync(LocalAuthenticationContext)
{
//TODO:在UserService.AuthenticateLocalAsync中处理AddshopperToBasketException
尝试
{
var user=新购物者(_dbConnLib,context.UserName,context.Password);
var索赔=新列表{新索赔(“acr_级别”、“0级”)、新索赔(“amr”、“匿名”)};
context.AuthenticateResult=新的AuthenticateResult(user.shopperid、user.MemberDetail.billToAddress.FirstName、claims);
}
捕获(shopperInitFromException ex)
{
context.AuthenticateResult=null;//表示用户名/密码失败
}
返回Task.FromResult(0);
}