注释之外的其他逻辑

注释之外的其他逻辑

本文介绍了运行除 [Authorize] 注释之外的其他逻辑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我正在为我的 .NET Core 项目使用 Microsoft.AspNetCore.Authentication.JwtBearerSystem.IdentityModel.Tokens.Jwt.

I'm using the Microsoft.AspNetCore.Authentication.JwtBearer and System.IdentityModel.Tokens.Jwt for my .NET Core project.

每当我生成一个新令牌时,我都会将其存储到数据库中.当用户退出时,我将其从数据库中删除以使其无效(我还通过作业从数据库中删除了过期的).当用户尝试访问受 [Authorize] 注释保护的路由时,我想检查该令牌是否存在于数据库中.如果没有,我会发送 401.

Whenever I generate a new token I store that to the database. When a user signs out, I remove it from the database to invalidate it (I also remove the expired ones from the database with a job). When a user tries to access a route protected by the [Authorize] annotation I want to check if that token exists in the database. If not, I send a 401.

在我的 Startup 中的 Configure 方法中,我正在调用 app.UseAuthentication()ConfigureServices> 方法我设置了对 [Authorize] 注释的验证(我试图对其进行评论以显示我想要实现的目标)

In my Startup in the Configure method I'm calling app.UseAuthentication() and in the ConfigureServices method I setup the validation for the [Authorize] annotation (I tried to comment it to show what I want to achieve)

services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtBearerOptions =>
{
    byte[] symmetricKey = Convert.FromBase64String("secretFromConfig");
    SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(symmetricKey);

    jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuerSigningKey = true,
        ValidateLifetime = true,
        ValidateIssuer = false,
        ValidateAudience = false,
        IssuerSigningKey = symmetricSecurityKey,
    };

    jwtBearerOptions.Events = new JwtBearerEvents()
    {
        OnTokenValidated = tokenValidatedContext =>
        {
            // inject my database repository
            ITokensRepository tokensRepository = tokenValidatedContext.HttpContext.RequestServices.GetRequiredService<ITokensRepository>();
            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

            // convert the token to a string
            string token = tokenHandler.WriteToken(tokenValidatedContext.SecurityToken);

            // read the username from the token payload
            Claim usernameClaim = tokenValidatedContext.Principal.Claims.FirstOrDefault(claim => claim.Type == "username");

            // assign if exists
            string username = usernameClaim?.Value;

            // fetch token from database
            object tokenInfo = await tokensRepository.GetUserTokenAsync(token, username);

            if (tokenInfo == null)
            {
                // return a 401 if token doesn't exist in database
                tokenValidatedContext.Fail("Invalid token.");
                // return new UnauthorizedResult();
            }
            else
            {
                tokenValidatedContext.Success();

                // controller methods can fetch it from here later on
                tokenValidatedContext.HttpContext.Items["username"] = username;
            }

            return Task.CompletedTask;
        }
    };
});

当我尝试使存储库调用的 OnTokenValidated 回调异步时,我收到错误消息

When I try to make the OnTokenValidated callback async for the repository call I get the error message

返回类型是'void'

我该如何解决?回调必须是异步的,因为我正在访问数据库.任何帮助将不胜感激!

How can I solve it? The callback has to be async because I'm accessing the database. Any help will highly appreciated!

推荐答案

我相信更好的方法之一是在您的授权中添加策略.(类似于如果您要创建索赔政策的处理方式)

I believe one of the better ways to do this is through adding a policy to your Authorization. (Similar to how it is handled if you want to create a claims policy)

如果您只想要某个授权标签的策略

If you want the policy only for certain authorize tage

Startup.cs

 services.AddAuthorization(authorizationOptions =>
 {
    authorizationOptions.AddPolicy(
    "MustHaveTokenInDb",
    policyBuilder =>
    {
       //add any other policy requirements here too including ones by default
       //eg policyBuilder.RequireAuthenticatedUser();
        policyBuilder.AddRequirements(
            new MustHaveTokenInDbRequirement());
    });
    //only if you want to register as the default policy
    authorizationOptions.DefaultPolicy = authorizationOptions.GetPolicy("MustHaveTokenInDb");
});

然后在授权

您使用的标签

[Authorize("MustHaveTokenInDB")]

您可以设置默认策略,允许您照常使用 Authorize 标签

You can set a default policy either which allows you to use the Authorize tag as normal

authorizationOptions.DefaultPolicy = authorizationOptions.GetPolicy("MustHaveTokenInDb");

您的需求类

public class MustHaveTokenInDbRequirement : IAuthorizationRequirement
    {
        public MustHaveTokenInDbRequirement ()
        {
        }
    }

处理程序类

 public class MustHaveTokenInDbHandler : AuthorizationHandler<MustHaveTokenInDbRequirement >
    {

        public MustHaveTokenInDbHandler ()
        {
            //your dependency injections
        }

        protected override Task HandleRequirementAsync(
            AuthorizationHandlerContext context,
            MustHaveTokenInDbRequirement requirement)
        {
           //your logic
            if (noTokenInDb)
            {
                context.Fail();
                return Task.CompletedTask;
            }


            // has token in db
            context.Succeed(requirement);
            return Task.CompletedTask;
        }
    }

在你的配置服务中你需要注册它:

In your configure services you need to register it:

services.AddScoped<IAuthorizationHandler, MustHaveTokenInDbHandler>();

这篇关于运行除 [Authorize] 注释之外的其他逻辑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 15:47