C# 如何使用自定义用户服务添加对IdentityServer 3的访问令牌的声明
我试图创建一个自定义用户,对其进行身份验证,然后使用identity server 3将用户声明返回到angular应用程序中。我查看了这些示例,特别是CustomUserService项目 编辑我已根据进度将问题更新为: 在starup.cs文件中,我有作用域和客户端加载C# 如何使用自定义用户服务添加对IdentityServer 3的访问令牌的声明,c#,claims-based-identity,identityserver3,C#,Claims Based Identity,Identityserver3,我试图创建一个自定义用户,对其进行身份验证,然后使用identity server 3将用户声明返回到angular应用程序中。我查看了这些示例,特别是CustomUserService项目 编辑我已根据进度将问题更新为: 在starup.cs文件中,我有作用域和客户端加载 var idServerServiceFactory = new IdentityServerServiceFactory() .UseInMemoryClients(Clients.
var idServerServiceFactory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get());
//.UseInMemoryUsers(Users.Get());
然后是UserServices.cs中的覆盖
public override Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
string hashedPassword = string.Empty;
string salt = string.Empty;
//pull users
using (IdentityModelContext ctx = new IdentityModelContext())
{
IIdSrvUserRepository ur = new IdSrvUserRepository(ctx);
Users = ur.GetAll().ToList();
}
//salt curent password
var user = Users.SingleOrDefault(x => x.UserName == context.UserName);
if (user != null)
{
salt = user.Salt;
hashedPassword = IqUtils.GenerateSaltedPassword(context.Password, salt);
if (user.UserName == context.UserName && hashedPassword == user.Password)
{
try
{
context.AuthenticateResult = new AuthenticateResult(user.Subject, user.UserName);
}
catch (Exception ex)
{
string msg = $"<-- Login Error: Message: {ex.Message}, Inner Exception:{ex.InnerException} --->";
myLogger log = new myLogger("IdentityServer");
}
}
}
return Task.FromResult(0);
}
这就是当我看到我在上下文中定义的声明时遇到的问题。RequestedClaimTypes
在claim.Type
中从来没有匹配项,因为它总是包含idsrv声明的基本属性
由于这是一个自定义数据库,因此索赔中的所有信息都存储在数据库的用户表中,而不是索赔表中。我试图将每个字段的值从user表映射到Claim值
更新
我已经返回并取消对范围的注释,并将以下声明添加到标识scopeType
new Scope
{
Name = "iuser",
DisplayName = "User",
Description = "Identifies the user",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>()
{
new ScopeClaim(Constants.ClaimTypes.Name, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.GivenName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.FamilyName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.Email, alwaysInclude: true),
}
}
新范围
{
Name=“iuser”,
DisplayName=“用户”,
Description=“标识用户”,
Type=ScopeType.Identity,
索赔=新清单()
{
新的ScopeClaim(Constants.ClaimTypes.Name,alwaysInclude:true),
新的ScopeClaim(Constants.ClaimTypes.GivenName,alwaysInclude:true),
新的ScopeClaim(Constants.ClaimTypes.FamilyName,alwaysInclude:true),
新的ScopeClaim(Constants.ClaimTypes.Email,alwaysInclude:true),
}
}
初始身份验证有效,在回调上我可以看到评估的作用域。然而,我仍然停留在如何从应用于这些作用域的DB中获取值的问题上。这部分代码(如预期)正在查找系统.Security.Claims.Claims
类型。现在,这是确定如何获取声明值的停止点,声明值是应用于我的用户并作为声明返回的属性
此时,我被重定向回angular应用程序,但accesstoken对象的用户信息为空
此时,如何将自己的值插入到上下文中。IssuedClaims
作为声明
提前感谢乍一看,您的angular客户端似乎没有配置为请求资源范围
iuser
您只是配置了请求名称
标识范围。将该作用域添加到客户端允许的作用域列表iqimplicit
,并确保将该作用域添加到angular应用程序的客户端配置中。通过进一步研究,我终于能够找到一种添加声明的方法
在GetProfileDataAsync()
上的UserService
类中,我最终能够使用以下命令创建和添加声明
var user = Users.SingleOrDefault(x => x.Subject == context.Subject.GetSubjectId());
if (user != null)
{
try
{
//add subject as claim
var claims = new List<Claim>
{
new Claim(Constants.ClaimTypes.Subject, user.Subject),
};
//get username
UserClaim un = new UserClaim
{
Subject = Guid.NewGuid().ToString(),
ClaimType = "username",
ClaimValue = string.IsNullOrWhiteSpace(user.UserName) ? "unauth" : user.UserName
};
claims.Add(new Claim(un.ClaimType, un.ClaimValue));
//get email
UserClaim uem = new UserClaim
{
Subject = Guid.NewGuid().ToString(),
ClaimType = "email",
ClaimValue = string.IsNullOrWhiteSpace(user.EmailAddress) ? string.Empty : user.EmailAddress
};
context.IssuedClaims = claims;
}
catch (Exception ex)
{
string msg = $"<-- Error Getting Profile: Message: {ex.Message}, Inner Exception:{ex.InnerException} --->";
myLogger log = new myLogger("IdentityServer");
}
}
//return Task.FromResult(context.IssuedClaims);
return Task.FromResult(0);
请注意,此处之所以使用$apply()
,只是因为此代码存在于应用程序中使用的指令中
我不确定这是否是添加声明的最佳实现,但这种方法确实有效。目前,我将暂缓将此标记为答案,看看是否有更好的方法。关于您似乎正在尝试做的事情的一些评论 1您正在复制一个现有范围,即
概要文件
范围。
如果您想要的所有声明都在OIDC标准范围内(此处:profile
/email
),则无需定义自己的范围。您在iuser
标识范围中声明的声明已包含在标准中的配置文件
范围中。因此,只需请求配置文件
范围,并允许您的客户请求该范围
标准范围及其索赔内容:
2客户端配置上的AllowedScopes
配置有点错误。
改为使用以下常量
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
}
AllowedScopes=新列表
{
Constants.StandardScopes.OpenId,
常量.StandardScopes.Profile,
Constants.StandardScopes.Email,
}
另请参见此示例配置。
3您还没有真正展示如何获取id_代币。。
。。但请记住向idsrv提供您想要回id_令牌的请求,包括来自概要文件范围的索赔。对/authorize
、/userinfo
或/token
端点的请求必须包含一个范围
参数,其值至少为openid profile
例如,像Brock A.在他的oidc js客户端库中所做的那样:
根据您的回复,索赔的值将从包含这些值的db表中导出,如AspNetIdentity?我的方法不同之处在于,这些值都作为属性存储在用户表中。(无标识数据库)正确的方法是否在Scope.cs类中派生这些值并将它们添加到Scope.cs类中?因为它们实际上是自定义属性,所以我不需要将它们映射到标准作用域,但可以反过来传入自定义作用域?在我当前的方法(上面的代码)中,声明是在资源客户机vs和identity上传递的。(我知道这是不对的)。如何将值映射到声明是IUserService
实现的目的。示例:在该示例中,请求的声明(由您请求的范围定义)与内存中的列表用户匹配。通常,这些都是从一个类似db的数据库中获取的:一个用户表。
new Scope
{
Name = "iuser",
DisplayName = "User",
Description = "Identifies the user",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>()
{
new ScopeClaim(Constants.ClaimTypes.Name, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.GivenName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.FamilyName, alwaysInclude: true),
new ScopeClaim(Constants.ClaimTypes.Email, alwaysInclude: true),
}
}
var user = Users.SingleOrDefault(x => x.Subject == context.Subject.GetSubjectId());
if (user != null)
{
try
{
//add subject as claim
var claims = new List<Claim>
{
new Claim(Constants.ClaimTypes.Subject, user.Subject),
};
//get username
UserClaim un = new UserClaim
{
Subject = Guid.NewGuid().ToString(),
ClaimType = "username",
ClaimValue = string.IsNullOrWhiteSpace(user.UserName) ? "unauth" : user.UserName
};
claims.Add(new Claim(un.ClaimType, un.ClaimValue));
//get email
UserClaim uem = new UserClaim
{
Subject = Guid.NewGuid().ToString(),
ClaimType = "email",
ClaimValue = string.IsNullOrWhiteSpace(user.EmailAddress) ? string.Empty : user.EmailAddress
};
context.IssuedClaims = claims;
}
catch (Exception ex)
{
string msg = $"<-- Error Getting Profile: Message: {ex.Message}, Inner Exception:{ex.InnerException} --->";
myLogger log = new myLogger("IdentityServer");
}
}
//return Task.FromResult(context.IssuedClaims);
return Task.FromResult(0);
$scope.mgr.oidcClient.loadUserProfile($scope.mgr.access_token)
.then(function (userInfoValues) {
$scope.profile = userInfoValues;
$scope.fullName = $scope.profile.given_name + ' ' + $scope.profile.family_name;
checkAdmin($scope.profile.sys_admin);
$scope.$apply();
});
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
}