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

时间:2018-09-24 14:46:36

标签: asp.net-core-2.0 asp.net-authorization

我有一个使用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 DB获取信息(如上所述)以进行检查,而且我在网上搜索的所有内容几乎都是带有静态数据的简单“年龄验证者”。

我已经尝试了一些方法,但是我可能只是一团糟(对于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()));
        });

有什么小窍门将我推向正确的方向吗?

1 个答案:

答案 0 :(得分:2)

[ { "id": 1, "name": "soubhagya", "company_name": "google" }, { "id": 2, "name": "nihar", "company_name": "facebook" } ] AuthorizationRequirement中都不需要重复进行令牌检查的逻辑。

只需创建一个虚拟授权要求,其中没有任何内容即可:

AuthorizationHandler

然后使用public class TokenValidationAuthorizeAttribute : IAuthorizationRequirement { // remove codes here } 来请求DependencyInjection

IUserService

要使ASP.NET Core意识到它应该检查处理程序,我们还需要添加一个授权配置:

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);

         // ...

    }
}

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

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

现在,用services.AddSingleton<IAuthorizationHandler,TokenValidationHandler>(); services.AddScoped<IUserService,YourUserServiceImplementation>(); 保护要验证TokenOk的操作,它将按预期工作。