Asp.net web api 如何在IdentityServer4中在运行时添加/管理用户声明

Asp.net web api 如何在IdentityServer4中在运行时添加/管理用户声明,asp.net-web-api,asp.net-core,authorization,identityserver4,claims,Asp.net Web Api,Asp.net Core,Authorization,Identityserver4,Claims,我正在尝试在新项目中使用IdentityServer4。我在PluralSight视频“了解ASP.NET核心安全性”中看到,IdentityServer4可以与基于声明的安全性一起使用,以保护web API。我已将IdentityServer4设置为单独的项目/解决方案 我还看到,您可以添加一个IProfileService,以向IdentityServer4返回的令牌添加自定义声明 一个计划是向用户添加新的声明,以允许他们访问api的不同部分。但是,我不知道如何从api项目管理Identit

我正在尝试在新项目中使用IdentityServer4。我在PluralSight视频“了解ASP.NET核心安全性”中看到,IdentityServer4可以与基于声明的安全性一起使用,以保护web API。我已将IdentityServer4设置为单独的项目/解决方案

我还看到,您可以添加一个IProfileService,以向IdentityServer4返回的令牌添加自定义声明

一个计划是向用户添加新的声明,以允许他们访问api的不同部分。但是,我不知道如何从api项目管理IdentityServer上用户的声明。我想我应该调用IdentiotyServer4来添加和删除用户声明

此外,这通常是一种好方法,因为我不确定允许客户端出于其自身的内部安全目的向IdentityServer添加声明是否有意义,并且可能会导致冲突(例如多个客户端使用“角色”声明和值为“admin”的声明)。也许我应该在api项目中本地处理安全性,然后使用“sub”声明来查找它们

有没有人对此有好的方法


谢谢

老问题,但仍然相关。正如leastprivilege在评论中所说的那样

声明涉及的是身份,而不是权限

这听起来是正确的,但标识也可能包含它是什么类型的用户(管理员、用户、经理等),可以用来确定API中的权限。也许设置具有特定权限的用户角色?基本上,如果CLIENT1 Admin不应该具有与CLIENT2 Admin相同的权限,您还可以在客户端之间拆分角色以获得更多控制

因此,在
IProfileService
中将您的角色作为声明传递

public class ProfileService : IProfileService
{
    private readonly Services.IUserService _userService;

    public ProfileService(Services.IUserService userService)
    {
        _userService = userService;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        try
        {
            switch (context.Client.ClientId)
            {
                //setup profile data for each different client
                case "CLIENT1":
                {
                    //sub is your userId.
                    var userId = context.Subject.Claims.FirstOrDefault(x => x.Type == "sub");

                    if (!string.IsNullOrEmpty(userId?.Value) && long.Parse(userId.Value) > 0)
                    {
                        //get the actual user object from the database
                        var user = await _userService.GetUserAsync(long.Parse(userId.Value));

                        // issue the claims for the user
                        if (user != null)
                        {
                            var claims = GetCLIENT1Claims(user);

                            //add the claims
                            context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
                        }
                    }
                }
                break;
                case "CLIENT2":
                {
                    //...
                }
            }
        }
        catch (Exception ex) 
        {
            //log your exceptions
        }
    }

    // Gets all significant user claims that should be included
    private static Claim[] GetCLIENT1Claims(User user)
    {
        var claims = new List<Claim>
        {
            new Claim("user_id", user.UserId.ToString() ?? ""),
            new Claim(JwtClaimTypes.Name, user.Name),
            new Claim(JwtClaimTypes.Email, user.Email ?? ""),
            new Claim("some_other_claim", user.Some_Other_Info ?? "")
        };

        //----- THIS IS WHERE ROLES ARE ADDED ------
        //user roles which are just string[] = { "CLIENT1-Admin", "CLIENT1-User", .. }
        foreach (string role in user.Roles)
            claims.Add(new Claim(JwtClaimTypes.Role, role));

        return claims.ToArray();
    }
}
上述声明也可以在身份验证时传递,例如,如果您正在使用带有自定义
ResourceOwnerPasswordValidator
的ResourceOwner设置。您可以在验证方法中以相同的方式传递声明,如下所示

context.Result = new GrantValidationResult(
    subject: user.UserId.ToString(),
    authenticationMethod: "custom",
    claims: GetClaims(user));
因此,正如leastprivilege所说,您不希望使用IdentityServer设置权限并将其作为声明传递(例如谁可以编辑什么记录),因为它们太具体,并且会使令牌变得混乱,但是设置角色会-

允许他们访问api的不同部分

这对于用户角色来说是非常好的


希望这能有所帮助。

声明是关于身份的,而不是权限的Hi@leastprivilege感谢链接。这个链接确实让你的观点非常清晰,但我仍然有点困惑,因为在这个视频中(这是你帮助创建的课程的一部分),索赔被用于授权。该视频被称为“基于声明的授权策略”。你不同意这个说法吗?您是否有任何链接指向正确组合IdentityServer4和授权的信息?再次感谢你,我还没看过普洛拉西特的课程。我要说的就是在我的博客帖子里。令牌不是很好的权限传输机制。如果您决定使用字符串集合(也称为ClaimsPrincipal)来保存内存中的authZ数据,这取决于您。看到答案是最新的:您知道如何在运行时添加用户吗?@Wouter Vanherck不确定您的用例,但您的意思是向您的系统注册新用户吗?注册与没有identity server的普通asp.net web应用完全相同(identity server更多用于验证现有用户)。只有登录才会发出令牌并进行验证,您应该为此调用identity server。对于visual studio中的默认asp.net模板,请检查AccountsController中的默认注册函数。如果这不能回答您的问题,请在堆栈溢出上创建一个新问题并链接到此处,我很乐意回答。@Wouter Vanherck没问题。您必须解释无法通过正常方法注册用户的含义。@Wouter Vanherck通常外部API的工作原理相同,您将identity server设置为资源所有者类型。您不会使用identity server来注册用户,只会对现有用户进行身份验证。因此,您通常使用api(客户端),调用在数据库中插入新用户的寄存器(匿名调用)。然后,当用户想要登录时,调用identity server端点/connect/token。当您设置identityserver时,您需要设置调用API的验证(安全-首选CORS和ssl)以检查用户名和密码是否存在。@Wouter Vanherck检查我的配置文件,我有一个关于资源所有者设置的非常全面的答案(IdentityServer 4注册UserService并使用asp.net core从数据库获取用户)。您只需更改userRepository.FindAync()调用即可调用api,在第三方api中找到用户并将其返回IdentityServer。希望有帮助
context.Result = new GrantValidationResult(
    subject: user.UserId.ToString(),
    authenticationMethod: "custom",
    claims: GetClaims(user));