包含访问令牌时如何从客户端应用程序中的 IdentityServer 获取用户 ID?
How to get user id from IdentityServer in client app when including access token?
我已经实现了一个基于 IdentityServer3 的身份验证服务和一个简单的 MVC 客户端应用程序以及一个由身份验证服务保护的购物者 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?
我想我可能有答案了。到目前为止,据我所知,我在 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);
}
我在 AuthenticateResult 中设置声明的 AuthenticateLocalAsync 代码在我的客户端应用程序代码中从未见过,如下所示:
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);
}
我已经实现了一个基于 IdentityServer3 的身份验证服务和一个简单的 MVC 客户端应用程序以及一个由身份验证服务保护的购物者 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?
我想我可能有答案了。到目前为止,据我所知,我在 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);
}
我在 AuthenticateResult 中设置声明的 AuthenticateLocalAsync 代码在我的客户端应用程序代码中从未见过,如下所示:
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);
}