简体   繁体   English

基于JWT的.Net MVC核心策略的授权

[英].Net MVC Core Policy based authorization with JWT

I'm trying to setup my authorization policy with a jwt based token for my apis. 我正在尝试为基于api的基于jwt的令牌设置授权策略。 I have two controllers, used by separate apis. 我有两个控制器,分别用于不同的API。 I need to make sure a user can only access the ones that he/she is allowed to use. 我需要确保用户只能访问他/她被允许使用的用户。 So I figured I'd go with policy based authorization 所以我想我会选择基于策略的授权

    [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
    }

Adding policies on Startup 在启动时添加策略

    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

So my question is, where is the best place to call a stored procedure to check the database for the users application permission. 所以我的问题是,调用存储过程以检查数据库中用户应用程序权限的最佳位置是哪里? Reading from the following, ( https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.1 ) , it details the use of the claims from the token. 从以下内容中阅读( https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/policies?view=aspnetcore-2.1 ),它详细说明了令牌中的声明的使用。

Right now what I have with the JWT token that I save is the userid, first name, last name and email, that's it. 现在,我所保存的JWT令牌具有的是用户ID,名字,姓氏和电子邮件,仅此而已。

The best place to check authentication and authorization in ActionFilter, you can check auth policy in database side and also with JWT. 在ActionFilter中检查身份验证和授权的最佳位置,您可以在数据库端以及JWT中检查身份验证策略。

If you want to authorise your controller, you have to use a middle ware ( ActionFilterAttribute ), which will detect user's http request and validate them by decoding user's token. 如果要授权控制器,则必须使用中间件( ActionFilterAttribute ),该中间件将检测用户的http请求并通过解码用户的令牌来验证它们。 you can filter all http methods (GET,POST,PUT,DELETE...etc), and can implement your own authorisation logic for specific http method. 您可以过滤所有HTTP方法(GET,POST,PUT,DELETE等),并可以为特定的HTTP方法实现自己的授权逻辑。

AuthorizationRequiredAttribute.cs AuthorizationRequiredAttribute.cs

NB: here all codes are not relevant to your problem. 注意:此处所有代码均与您的问题无关。 but hope you'll understand how actually i filter get/post request with condition. 但希望您能理解我实际上是如何使用条件过滤获取/发布请求的。

[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 HomeController.cs

Now you can use AuthorizationRequiredAttribute as api/controller filter service. 现在,您可以将AuthorizationRequiredAttribute用作api /控制器过滤器服务。 i have modified your controller and see the Message method 我已经修改了您的控制器并查看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!");
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM