ASPNET Core 2 中的自定义策略身份验证(jwt 身份验证)

Custom policy auth in ASPNET Core 2 (jwt auth)

我有一个使用 JWT 身份验证的简单应用程序 (API)。我已经实现了一种方法来根据数据库中的某些信息检查令牌是否仍然有效。它看起来像这样 ->

        //Check if the token is valid
        var tokenStamp = int.Parse(claimsIdentity.FindFirst(JwtRegisteredClaimNames.Iat)?.Value);
        if (userDto.PasswordChangedAt > tokenStamp)
        {
            ModelState.AddModelError("SessionExpired", "Please relog.");
            return BadRequest(ModelState);
        }
        //Done checking token

我已经尝试了好几个小时来将此代码移动到一个策略中,所以与其编写所有我可以拥有类似

的东西
[Authorize(Policy="MYPOLICY")]

我的问题是我需要从 SQL 数据库(如上所述)获取信息来进行检查,我在网上搜索的几乎所有内容都只是一个简单的 "age verifier"静态数据。

我已经尝试了一些东西,但我可能只是弄得一团糟(对 netcore 来说还是有点新)。这里什么都没有 ->

public class TokenValidationAuthorizeAttribute : IAuthorizationRequirement
{
    public void TokenChangeValidation(AuthorizationHandlerContext context, UserService userService)
    {
        //var claimsIdentity = this.User.Identity as ClaimsIdentity;
        var tokenCreationDate = int.Parse(context.User.FindFirst(c => c.Type == JwtRegisteredClaimNames.Iat).Value);
        var userId = int.Parse(context.User.FindFirst(c => c.Type == ClaimTypes.Name).Value);
        var user = userService.GetById(userId, false);
        var userInfo = Mapper.Map<UserDto>(user);
        var tokenStamp = int.Parse(context.User.FindFirst(JwtRegisteredClaimNames.Iat)?.Value);

        TokenIssuedAt = tokenStamp;


    }

    public int TokenIssuedAt { get; set; }

    internal IAuthorizationRequirement TokenChangeValidation(AuthorizationHandlerContext context)
    {
        throw new NotImplementedException();
    }
}

public class TokenValidationHandler : AuthorizationHandler<TokenValidationAuthorizeAttribute>
{

    const string POLICY_PREFIX = "TokenValidation";
    private IUserService _userService;

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,TokenValidationAuthorizeAttribute requirement)
    {
        var userService = _userService;

        //var claimsIdentity = this.User.Identity as ClaimsIdentity;
        var tokenCreationDate = int.Parse(context.User.FindFirst(c => c.Type == JwtRegisteredClaimNames.Iat).Value);
        var userId = int.Parse(context.User.FindFirst(c => c.Type == ClaimTypes.Name).Value);
        var user = userService.GetById(userId, false);
        var userInfo = Mapper.Map<UserDto>(user);
        var tokenStamp = int.Parse(context.User.FindFirst(JwtRegisteredClaimNames.Iat)?.Value);

        if (userInfo.PasswordChangedAt >= requirement.TokenIssuedAt)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

但我无法创建 TokenValidationAuthorizeAttribute 的新实例,因为我无法从 ConfigureServices 传递上下文,因此以下代码肯定不起作用。

        services.AddAuthorization(options =>
        {
            options.AddPolicy("TokenOk", policy => policy.Requirements.Add(new TokenValidationAuthorizeAttribute()));
        });

有什么提示可以帮助我朝着正确的方向前进吗?

AuthorizationRequirementAuthorizationHandler 中不需要重复的令牌检查逻辑。

只需创建一个内部没有任何内容的虚拟授权要求:

public class TokenValidationAuthorizeAttribute : IAuthorizationRequirement
{
    // remove codes here
}

并使用 DependencyInjection 请求 IUserService :

public class TokenValidationHandler : AuthorizationHandler<TokenValidationAuthorizeAttribute>
{
    private IUserService _userService;

    public TokenValidationHandler(IUserService userService) {
        this._userService = userService;
    }

    // ...

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenValidationAuthorizeAttribute requirement)
    {
         // check the token-code of current user against the one from db here ...

         // the toekn-code of current user
         var claimsIdentity = context.User.Identity as ClaimsIdentity;
         var tokenCreationDate = int.Parse(context.User.FindFirst(c => c.Type == JwtRegisteredClaimNames.Iat).Value);

         // ...

    }
}

为了让 ASP.NET 核心实现它应该检查处理程序,我们还需要添加授权配置:

services.AddAuthorization(opts=>
{
    opts.AddPolicy("TokenOk", policy => policy.Requirements.Add(new TokenValidationAuthorizeAttribute()));
});

最后,不要忘记注册授权处理程序和 IUserService :

services.AddSingleton<IAuthorizationHandler,TokenValidationHandler>();
services.AddScoped<IUserService,YourUserServiceImplementation>();

现在,用 [Authorize("TokenOk")] 保护要验证 TokenOk 的操作,它将按预期工作。