我正在尝试为基于api的基于jwt的令牌设置授权策略。我有两个控制器,分别用于不同的API。我需要确保用户只能访问他/她被允许使用的用户。所以我想我会选择基于策略的授权
[Authorize(Policy = "API1")]
[Route("api1/endpoint")]
public class API1Controller : Controller
{
// my actions for api 1
}
[Authorize(Policy = "API2")]
[Route("api2/endpoint")]
public class API2Controller : Controller
{
// my actions for api 2
}
在启动时添加策略
services.AddAuthorization(options => {
options.AddPolicy("API1User", policy => policy.Requirements.Add(new ApplicationTypeRequirement(ApplicationType.API1)));
options.AddPolicy("API2User", policy => policy.Requirements.Add(new ApplicationTypeRequirement(ApplicationType.API2)));
});
// Adding handlers after this
所以我的问题是,调用存储过程以检查数据库中用户应用程序许可的最佳位置是哪里?从下面的(https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.1)中读取内容,它详细说明了令牌中声明的使用。
现在,我所保存的JWT令牌具有的是用户ID,名字,姓氏和电子邮件,仅此而已。
答案 0 :(得分:0)
在ActionFilter中检查身份验证和授权的最佳位置,您可以在数据库端以及JWT中检查身份验证策略。
如果要授权控制器,则必须使用中间件( ActionFilterAttribute ),该中间件将检测用户的http请求并通过解码用户的令牌来验证它们。您可以过滤所有http方法(GET,POST,PUT,DELETE等),并可以为特定的http方法实现自己的授权逻辑。
AuthorizationRequiredAttribute.cs
N.B:此处所有代码均与您的问题无关。但希望您能理解我实际上是如何使用条件过滤获取/发布请求的。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
private readonly IAccessTokenServices _accessTokenServices;
private readonly IPermissionServices _permissionServices;
private readonly IAuditLogServices _auditLogServices;
private IConfiguration _config;
public AuthorizationRequiredAttribute(IAccessTokenServices accessTokenServices, IPermissionServices permissionServices,
IAuditLogServices auditLogServices,IConfiguration config)
{
_accessTokenServices = accessTokenServices;
_config = config;
_permissionServices = permissionServices;
_auditLogServices = auditLogServices;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
try
{
if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
as JwtSecurityToken;
var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
{
if (expireDate < DateTime.Now)
{
context.Result = new UnauthorizedResult();
}
}
else
{
var accessToken = _accessTokenServices
.Details(x => x.Token == context.HttpContext.Request.Headers[Constants.HttpHeaders.Token]);
if (accessToken != null)
{
if (accessToken.ExpiresOn < DateTime.Now)
{
_accessTokenServices.Delete(accessToken);
context.Result = new UnauthorizedResult();
}
else
{
var userId = Convert.ToInt32(token.Claims.First(claim => claim.Type == Constants.JwtClaims.UserId).Value);
var userTypeId = Convert.ToInt32(token.Claims.First(claim => claim.Type == Constants.JwtClaims.UserTypeId).Value);
if (accessToken == null)
{
context.Result = new UnauthorizedResult();
}
else if (!_permissionServices.IsPermissionExist(context.HttpContext.Request.Path.ToString(), userTypeId))
{
context.Result = new StatusCodeResult((int)HttpStatusCode.NotAcceptable);
}
else
{
_auditLogServices.Save(context.HttpContext.Request.Path.ToString(), userId);
accessToken.ExpiresOn = DateTime.Now.AddMinutes(Convert.ToInt16(_config["Jwt:ExpiresOn"]));
_accessTokenServices.UpdateExpireTime(accessToken);
}
}
}
else
{
context.Result = new UnauthorizedResult();
}
}
}
else
{
context.Result = new NotFoundResult();
}
}
catch (Exception ex)
{
context.Result = new BadRequestResult();
}
base.OnActionExecuting(context);
}
}
}
HomeController.cs
现在,您可以将AuthorizationRequiredAttribute用作api /控制器过滤器服务。我已经修改了您的控制器并查看Message方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Chat.Controllers
{
[Route("api/home")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpGet("message"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
public IActionResult Message()
{
return Ok("Hello World!");
}
}
}