如何使用基于策略的授权将所需的声明附加到令牌?

时间:2021-07-08 06:16:17

标签: asp.net-core jwt authorization

我正在尝试在我的 Web API 中实施基于策略的授权。我想弄清楚的是,在用户的登录操作中为用户生成令牌时,如何确定应将哪些声明添加到令牌中。我应该在数据库中存储每个用户的索赔信息,还是我误解了一些概念?

这是我用来生成 JWT/刷新令牌对的方法:

public async Task<AuthenticationResponse> GenerateTokenPairForUserAsync(User user)
{
    var jwtTokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
    var guid = Guid.NewGuid().ToString();
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Email),
            new Claim(ClaimTypes.Sid, user.Id.ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim(ClaimTypes.Role, user.RoleId.ToString()),
            new Claim(JwtRegisteredClaimNames.Jti, guid)
        }),
        Expires = DateTime.UtcNow.Add(_jwtConfig.TokenLifetime),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
    };

    var token = jwtTokenHandler.CreateToken(tokenDescriptor);
    var jwtToken = jwtTokenHandler.WriteToken(token);

    var refreshToken = new RefreshToken
    {
        JwtId = token.Id,
        IsUsed = false,
        IsRevoked = false,
        UserId = user.Id,
        CreationDate = DateTime.UtcNow,
        ExpiryDate = DateTime.UtcNow.Add(_refreshTokenConfig.TokenLifetime),
        Token = RandomString(25) + Guid.NewGuid()
    };

    await _refreshTokenRepository.CreateAsync(refreshToken);

    return new AuthenticationResponse
    {
        Token = jwtToken,
        Success = true,
        RefreshToken = refreshToken.Token
    };
}

1 个答案:

答案 0 :(得分:1)

你需要做一些事情来实现这一点:

  • 您应该了解哪些客户端可以接收哪些声明。客户端,即调用您的授权端点的应用程序。如果您只有一个,那么这不是问题,但是如果您有多个,则应该在数据库中的某个位置保留给定客户端应在令牌中接收的所有声明的列表。

  • 将范围映射到声明很方便。在授权请求中,您可以请求范围,这些范围本质上是一组声明。如果您的客户(或客户)实际上可以请求具有不同范围的令牌,您将需要它。例如。您可能想要请求一个令牌,该令牌可用于执行一些更敏感的操作,也许更改用户的电子邮件。然后,您可以要求服务器发出可能具有范围“admin”的令牌,其中包括声明 can_change_email: true。然后可以使用此声明来执行授权决策。

  • 最后,您需要知道,对于每个索赔,数据的来源是什么。因此,一旦您知道您的令牌必须包含声明 claim1claim2claim3,那么您必须知道从何处获取数据。这可以是硬编码的 - 例如您实现了一个 getValueForClaim2() 方法,该方法知道它应该从数据库中读取数据(例如,它是用户的电话号码)。或者您可以创建一些更复杂的解决方案,在其中保留一些到 claimProviders 的映射,然后实现这些提供程序。最后,您从哪里获取数据完全取决于您 - 这可以是数据库、文件、API 调用,或者根据某些输入计算出的值。

查看有关我们在 Curity 撰写的声明的这些资源:https://curity.io/resources/claims/ 如果您想了解有关此主题的更多信息。