自定义授权适用于操作级别,但不适用于控制器级别

Posted

技术标签:

【中文标题】自定义授权适用于操作级别,但不适用于控制器级别【英文标题】:Custom Authorize works on action level but not on controller level 【发布时间】:2016-04-07 02:22:56 【问题描述】:

据我所知,使用授权属性装饰的控制器内部的所有操作默认情况下都将采用相同的属性值,(例如,如果控制器授权属性角色 = admin,则所有未使用任何属性装饰的操作都会自动执行相同的角色 = 管理员),但这个逻辑在我的情况下不起作用

这里是我的自定义授权详情

 public class CustomAuthorize : AuthorizeAttribute
    
        public string Url  get; set; 
        public string Claims  get; set; 

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        
            if (!httpContext.User.Identity.IsAuthenticated)
            
                return false;
            
            else if (!string.IsNullOrWhiteSpace(Claims))
            
                var claims = httpContext.GetOwinContext().Authentication.User.HasClaim(t => t.Type == "claim"
                && Claims.Split(',').Contains(t.Value));
                if (!claims)
                
                    return false;
                
                else
                    return true;
            
            else if (!string.IsNullOrWhiteSpace(Roles))
            
                var roles = httpContext.GetOwinContext().Authentication.User.HasClaim(t => t.Type == "role"
                && Roles.Split(',').Contains(t.Value));
                if (!roles)
                
                    return false;
                
                else
                    return true;
            
            return base.AuthorizeCore(httpContext);
        

        public bool IsAuthorized(string claim)
        
            if (!string.IsNullOrEmpty(Claims))
                return Claims.Split(',').Contains(claim);
            return true;
        

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        
            if (!string.IsNullOrEmpty(Url))
                filterContext.Result = new RedirectResult(Url);
            else
                base.HandleUnauthorizedRequest(filterContext);
        

    

检查身份验证的辅助方法

 public static bool ActionIsAuthorized(this htmlHelper helper, string actionName, string controllerName)
        
            IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
            ControllerBase controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName) as ControllerBase;
            var controllerContext = new ControllerContext(helper.ViewContext.RequestContext, controller);
            var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
            var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
            AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
            foreach (var authAttribute in actionDescriptor
                .GetFilterAttributes(true)
                .Where(a => a is CustomAuthorize).Select(a => a as CustomAuthorize))
            
                authAttribute.OnAuthorization(authContext);
                if (authContext.Result != null)
                    return false;
            
            return true;
        

在视图中的用法

@if(Html.ActionIsAuthorized("Index","Appointment", new area="Employee"))
    @Html.ActionLink("Appointments","Index","Appointment",new area = "Employee")

当我使用上面的代码如下时,它不起作用(约会链接仍然显示)

[CustomAuthorize(Claims="Add Appointment",Url="~/Employee/Home/Login")]
public class AppointmentController: BaseController

      public ActionResult Index()
      
          // code here
      

如果我按以下方式使用它,它可以工作

public class AppointmentController: BaseController


      [CustomAuthorize(Claims="Add Appointment",Url="~/Employee/Home/Login")]
      public ActionResult Index()
      
          // code here
      

谁能告诉我为什么在我装饰控制器时默认情况下该操作不采用该属性?或者我错过了什么?

【问题讨论】:

“不起作用”是什么意思。您的意思是当您在类级别应用属性时,CustomAttribute 中的代码不会在“Index”方法上执行? @granadaCoder 它运行但不读取自定义属性值(函数 ActionIsAuthorized ) 【参考方案1】:

看起来问题出在您的自定义 ActionIsAuthorized html 帮助程序中。您只在操作描述符上寻找属性,而不是在控制器描述符上。所以请确保您也查看controllerDescriptor.GetCustomAttributes()

var actionAttributes = actionDescriptor.GetCustomAttributes(typeof(CustomAuthorize), true);
var controllerAttributes = controllerDescriptor.GetCustomAttributes(typeof(CustomAuthorize), true);
var attributes = actionAttributes.Concat(controllerAttributes).OfType<CustomAuthorize>().ToList();
foreach (var authAttribute in attributes)

    ...

【讨论】:

它工作了,但为什么该操作没有从控制器继承属性? 因为您使用的 GetCustomAttributes 方法只是在底层使用反射。反射是一个标准的 .NET 工件,它对 ASP.NET MVC 控制器和操作一无所知,更重要的是它们之间存在的关系以及这些授权属性的继承规则。顺便说一句,您可能应该考虑在那里使用一些缓存,因为每个视图上的那些反射调用可能会破坏您的应用程序的性能。如您所知,反射很慢。

以上是关于自定义授权适用于操作级别,但不适用于控制器级别的主要内容,如果未能解决你的问题,请参考以下文章

预授权不适用于控制器

android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 适用于应用程序级别,但不适用于活动级别。有啥线索吗?

Axios 发布请求适用于 Postman,但不适用于浏览器(它返回“错误 401-未授权”)

操纵杆控制器适用于编辑器,但不适用于构建游戏

Jquery Validation 适用于默认 [Required] 但不适用于自定义类

我的 webview 视频适用于模拟器,但不适用于设备