C# 除[授权]注释外,运行其他逻辑
我正在使用Microsoft.AspNetCore.Authentication.JwtBearer和System.IdentityModel.Tokens.Jwt进行.NET核心项目 每当我生成一个新的令牌时,我都会将其存储到数据库中。当用户注销时,我会将其从数据库中删除以使其无效(我还会使用作业从数据库中删除过期的用户)。当用户试图访问受C# 除[授权]注释外,运行其他逻辑,c#,.net-core,asp.net-core-webapi,adal,C#,.net Core,Asp.net Core Webapi,Adal,我正在使用Microsoft.AspNetCore.Authentication.JwtBearer和System.IdentityModel.Tokens.Jwt进行.NET核心项目 每当我生成一个新的令牌时,我都会将其存储到数据库中。当用户注销时,我会将其从数据库中删除以使其无效(我还会使用作业从数据库中删除过期的用户)。当用户试图访问受[Authorize]注释保护的路由时,我想检查数据库中是否存在该令牌。如果没有,我会寄401 在我启动的Configure方法中,我调用了app.UseA
[Authorize]
注释保护的路由时,我想检查数据库中是否存在该令牌。如果没有,我会寄401
在我启动的Configure
方法中,我调用了app.UseAuthentication()
,在ConfigureServices
方法中,我设置了[Authorize]
注释的验证(我试图对其进行注释以显示我想要实现的功能)
服务
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtBearerOptions=>
{
字节[]symmetricKey=Convert.FromBase64String(“secretFromConfig”);
SymmetricSecurityKey SymmetricSecurityKey=新的SymmetricSecurityKey(symmetricKey);
jwtBearerOptions.TokenValidationParameters=新的TokenValidationParameters()
{
ValidateSuersigningKey=true,
ValidateLifetime=true,
validateisuer=false,
ValidateAudience=false,
IssuerSigningKey=symmetricSecurityKey,
};
jwtBearerOptions.Events=newjwtbearerevents()
{
OnTokenValidated=tokenValidatedContext=>
{
//注入我的数据库存储库
iTokensRespository TokensRespository=tokenValidatedContext.HttpContext.RequestServices.GetRequiredService();
JwtSecurityTokenHandler tokenHandler=新的JwtSecurityTokenHandler();
//将令牌转换为字符串
string token=tokenHandler.WriteToken(tokenValidatedContext.SecurityToken);
//从令牌负载读取用户名
Claim usernameClaim=tokenValidatedContext.Principal.Claims.FirstOrDefault(Claim=>Claim.Type==“用户名”);
//如果存在,则分配
字符串username=usernameClaim?.Value;
//从数据库中获取令牌
object tokenInfo=wait tokensRepository.GetUserTokenAsync(令牌,用户名);
if(tokenInfo==null)
{
//如果数据库中不存在令牌,则返回401
tokenValidatedContext.Fail(“无效令牌”);
//返回新的未授权结果();
}
其他的
{
tokenValidatedContext.Success();
//控制器方法稍后可以从这里获取它
tokenValidatedContext.HttpContext.Items[“用户名”]=用户名;
}
返回Task.CompletedTask;
}
};
});
当我尝试使存储库调用的OnTokenValidated
回调异步时,我会收到错误消息
返回类型为“void”
我怎样才能解决它?回调必须是异步的,因为我正在访问数据库。任何帮助都将不胜感激 我认为更好的方法之一是在授权中添加策略。(与创建理赔保单时的处理方式类似) 如果您只想在某些情况下使用保险单 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");
});
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;
}
}
然后在
您使用的标签
[Authorize("MustHaveTokenInDB")]
您可以设置默认策略,该策略允许您正常使用授权标记
authorizationOptions.DefaultPolicy = authorizationOptions.GetPolicy("MustHaveTokenInDb");
您的需求类别
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");
});
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;
}
}
处理程序类
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");
});
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;
}
}
公共类必须具有TokenIndbHandler:AuthorizationHandler
{
公共必须具有令牌indbHandler()
{
//你的依赖注射
}
受保护的覆盖任务句柄请求同步(
授权HandlerContext上下文,
必须有标识(内部要求要求)
{
//你的逻辑
如果(不可忽略)
{
context.Fail();
返回Task.CompletedTask;
}
//在db中有令牌
成功(要求);
返回Task.CompletedTask;
}
}
在配置服务中,您需要注册它:
services.AddScoped<IAuthorizationHandler, MustHaveTokenInDbHandler>();
services.addScope();
谢谢您的回复!我更新了我的问题,我认为我找到了一个更好的解决方案:)这是一个有趣的解决方案,特别是如果您想添加一个额外的检查,您知道它不会在API的范围内改变。我喜欢我的答案中的方法的主要原因是它非常灵活,您可以堆叠策略,或者仅对某些请求运行策略。如果您有一个新的授权声明要检查,您可以很容易地将其添加进去。如果您有一个动态授权策略,该策略可能会发生很大变化,或者对于不同的请求需要不同的声明,我建议您使用与我的回答中类似的方法。您可以尝试将JWTBeareEvents修改为:OnTokenValidated=async tokenValidatedContext=>