【问题标题】:.Net MVC Core Policy based authorization with JWT.Net MVC Core Policy 基于 JWT 的授权
【发布时间】:2019-03-20 11:39:15
【问题描述】:

我正在尝试使用基于 jwt 的令牌为我的 api 设置我的授权策略。我有两个控制器,由单独的 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、名字、姓氏和电子邮件,仅此而已。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core-mvc asp.net-authorization


    【解决方案1】:

    在 ActionFilter 中检查身份验证和授权的最佳位置,您可以在数据库端检查身份验证策略,也可以使用 JWT。

    如果你想授权你的控制器,你必须使用一个中间件(ActionFilterAttribute),它会检测用户的http请求并通过解码用户的令牌来验证它们。您可以过滤所有 http 方法(GET、POST、PUT、DELETE...等),并且可以为特定的 http 方法实现自己的授权逻辑。

    AuthorizationRequiredAttribute.cs

    注意:这里所有的代码都与您的问题无关。但希望您能理解我实际上是如何根据条件过滤获取/发布请求的。

    [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/controller 过滤服务。我已经修改了您的控制器并查看 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!");
            }
        }
    }
    

    【讨论】:

    • 是你选择使用中间件的原因-ActionFilterAttribute 是因为这里我们需要使用dbContext(我们需要访问数据库)? Microsoft(docs.microsoft.com/en-us/aspnet/core/security/authorization/…) 介绍了一个使用授权处理程序的“AtLeast21”策略示例,我们是否也可以在那里使用 dbContext?
    • 是的@KevDing 你也可以使用 DbContext 来检查授权。
    猜你喜欢
    • 1970-01-01
    • 2019-08-05
    • 2020-12-01
    • 2020-07-21
    • 1970-01-01
    • 2019-03-18
    • 2016-12-14
    • 2019-01-04
    • 2020-02-16
    相关资源
    最近更新 更多