【问题标题】:How to implement some code in many actions of many controllers如何在许多控制器的许多动作中实现一些代码
【发布时间】:2017-07-07 15:16:04
【问题描述】:

我有带有动作的控制器,它与某些实体(驱动程序)一起工作。此外,每个司机都与身份资料相关联。

        public async Task<ActionResult> Details(int? id)
        {
            if ((id == null))
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            DriverDetailVM model = mapper.Map<DriverDetailVM>(db.Drivers.Find(id));
            if ((model == null))
            {
                return HttpNotFound();
            }
            return View(model);
        }

        public async Task<ActionResult> Edit(int? id = null, bool isNewUser = false)
        {
/////////
        }

如果用户具有“超级管理员”角色,则他可以访问具有任何 id 值的页面。如果用户具有“司机”角色,那么我们应该只有在 id 值与他的个人资料相同的情况下才能访问。我尝试在 ActionFilter 上实现它:

public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
    public string IdParamName { get; set; }
    public int DriverID { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.User.IsInRole("Driver"))
        {
            if (filterContext.ActionParameters.ContainsKey(IdParamName))
            {
                var id = filterContext.ActionParameters[IdParamName] as Int32;
                if (id != DriverID)
                    filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
            }
            else
                filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
        }
        else
            base.OnActionExecuting(filterContext);
    }
}

但是当我尝试使用这段代码时:

    [DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")]
    public async Task<ActionResult> Details(int? id)
    {

它不想被编译,因为

非静态字段、方法或 属性

如何实现?

【问题讨论】:

    标签: asp.net-mvc action-filter actionfilterattribute custom-action-filter


    【解决方案1】:

    属性参数在编译时评估,而不是在运行时评估。所以它们必须是编译时常量。您不能在运行时将值传递给操作属性。即在[DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")] 中,您正在传递DriverID = currentUser.DriverId。属性用作控制器/动作元数据,元数据需要在程序集中进行编译。这就是属性只能采用常量值的原因。

    你必须改变你的属性如下:

    1. 使用依赖注入注入您的服务,返回登录用户。
    2. 或实现自定义 Principal 并为其分配当前请求主体。

    如果您实施 CustomPrinicpal,您可以如下修改您的属性:

    public class DriverAccessActionFilterAttribute : ActionFilterAttribute
        {
            public string IdParamName { get; set; }
            private int DriverID { get; set; }
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {            
                if (filterContext.HttpContext.User.IsInRole("Driver"))
                {
                    var customPrincipal = filterContext.HttpContext.User as CustomPrincipal;
                    DriverID = customPrincipal.Id;
                    // Rest of you logic                
                }
                else
                    base.OnActionExecuting(filterContext);
            }
        }
    

    如果您选择 DI 路径,则可以使用以下 sn-p:

    public class DriverAccessActionFilterAttribute : ActionFilterAttribute
    {
        public string IdParamName { get; set; }
        private int DriverID { get; set; }
    
        public DriverAccessActionFilterAttribute(IYourIdentityProvider provider)
        {
            DriverID = provider.LoggedInUserID;
        }
    
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {            
            // Your logic
        }
    }
    

    然后将您的属性用作[DriverAccessActionFilter(IdParamName = "id")]

    【讨论】:

    • 欢迎您并尝试从AuthorizationFilterAttribute而不是ActionFilterAttribute开车。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多