C# 如何使用自定义用户服务添加对IdentityServer 3的访问令牌的声明

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.

我试图创建一个自定义用户,对其进行身份验证,然后使用identity server 3将用户声明返回到angular应用程序中。我查看了这些示例,特别是CustomUserService项目

编辑我已根据进度将问题更新为:

在starup.cs文件中,我有作用域和客户端加载

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,
}