【问题标题】:How to add/manage user claims at runtime in IdentityServer4如何在 IdentityServer4 运行时添加/管理用户声明
【发布时间】:2017-09-14 02:51:16
【问题描述】:

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

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

一个计划是向用户添加新声明,以授予他们对 api 不同部分的访问权限。但是我不知道如何从 api 项目管理 IdentityServer 上用户的声明。我假设我应该调用 IdentotyServer4 来添加和删除用户声明?

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

有人对此有好的方法吗?

谢谢

【问题讨论】:

  • 声明是关于身份的 - 不是权限leastprivilege.com/2016/12/16/identity-vs-permissions
  • 嗨@leastprivilege 感谢您的链接。该链接确实使您的意见非常清楚,但我仍然有些困惑,因为在此视频中(这是您帮助创建的课程的一部分)声明用于授权。该视频被称为“基于声明的策略授权”。你不同意这种方法吗?您是否有任何有关正确组合 IdentityServer4 和授权的信息的链接?再次感谢app.pluralsight.com/…
  • 我还没有看过 PluralSight 课程。我要说的都在我的博文中。令牌不是一个好的权限传输机制。如果您决定使用字符串集合(又名 ClaimsPrincipal)来保存内存中的 authZ 数据 - 这取决于您。

标签: asp.net-web-api asp.net-core authorization identityserver4 claims


【解决方案1】:

老问题,但仍然相关。正如 cmets 中所说的最小特权

声明是关于身份 - 而不是权限

这听起来不错,但身份也可能包含可用于确定 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();
    }
}

然后将[Authorize] 属性添加到您的控制器以获得您的特定权限。这仅允许特定角色访问它们,因此设置您自己的权限。

[Authorize(Roles = "CLIENT1-Admin, CLIENT2-Admin, ...")]
public class ValuesController : Controller
{
    //...
}

上述这些声明也可以通过身份验证传递,例如,如果您使用带有自定义 ResourceOwnerPasswordValidator 的 ResourceOwner 设置。您可以像这样在 Validation 方法中以相同的方式传递声明。

context.Result = new GrantValidationResult(
    subject: user.UserId.ToString(),
    authenticationMethod: "custom",
    claims: GetClaims(user));

所以就像最小特权说的那样,你不想使用 IdentityServer 来设置权限并将其作为声明传递(比如谁可以编辑什么记录),因为它们太具体并且使令牌混乱,但是设置角色 -

授予他们访问 api 不同部分的权限。

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

希望这会有所帮助。

【讨论】:

  • 看到答案是最新的:关于如何在运行时添加用户的任何想法?
  • @Wouter Vanherck 不确定您的用例,但您的意思是向您的系统注册新用户吗?注册与没有身份服务器的普通 asp.net Web 应用程序完全相同(身份服务器更多地用于验证现有用户)。只有登录才会发出令牌并进行验证,您应该调用身份服务器。查看 Visual Studio 中默认 asp.net 模板的 AccountsController 中的默认注册功能。如果这不能回答您的问题,请创建一个有关堆栈溢出的新问题并将其链接到此处,我很乐意回答。
  • @Wouter Vanherck 没问题。您将不得不解释无法通过常规方法注册用户的意思。
  • @Wouter Vanherck 通常外部 API 的工作方式相同,并且您将身份服务器设置为资源所有者类型。您不会使用身份服务器来注册用户,而只会对现有用户进行身份验证。所以你正常使用你的api(客户端),调用你的注册(匿名调用),将新用户插入你的数据库。然后,当用户想要登录时,您调用您的身份服务器端点 /connect/token。我在设置身份服务器时需要设置调用 API 的验证(安全地 - 首选 CORS 和 ssl)以检查用户名和密码是否存在。
  • @Wouter Vanherck 检查我的个人资料,我有一个关于资源所有者设置的非常全面的答案(IdentityServer 4 注册 UserService 并使用 asp.net 核心从数据库中获取用户)。您只需更改 userRepository.FindAync() 调用即可调用您的 api,在 3rd 方 API 中找到用户并将其返回给 IdentityServer。希望对你有帮助
猜你喜欢
  • 1970-01-01
  • 2020-03-27
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 2020-08-20
相关资源
最近更新 更多