将字符串规则映射到LINQ表达式,包括包含自己的授权方法的表达式

时间:2017-12-31 17:22:21

标签: c# asp.net-mvc linq

在MVC应用程序中,我想实现一组规则,超级用户可以创建,读取,更新和删除。

每条规则明确允许/禁止用户以以下格式执行操作:

<Allow || Deny> userId <action_key> <condition>

操作键类似"DoSomeAction"字符串。

然后我打算在控制器内部使用这些规则进行授权 授权。例如:

//GET ViewProduct/id
public ActionResult ViewProduct(string productId)
{
    var product = // get product from repository;
    if(RulesAuthorizer.Authorise("ViewProduct", User.Identity.GetUserId(), product){

    //proceed to product... JSON or partial view, etc.
    }
    return new HttpStatusCodeResult(403);
}

ViewProduct是上面的示例action_key。

Authorise(string action_key, string userId, object ruleArg = null)方法中,我会从数据库加载此操作键的所有用户相关规则,并决定是否允许该用户。

但是,这确实是个问题,我怎么能将规则的条件用作字符串。例如,条件是:

用户必须是该组的成员&#34;客户&#34;并且产品不得属于&#34;奶酪&#34;或

自定义方法结果,例如如果产品是由组X添加的,而组Y必须看不到它,我可以使用我的方法Product.GetAddedBy()并在LINQ表达式中包含此方法。

我如何为每个规则存储字符串条件,然后从它们构建LINQ表达式?

我打算在可选的ruleArg参数中传递有问题的对象(示例中的Product)。

对于存储字符串的方便方法,我们非常感谢任何想法,可以在运行时使用LINQ表达式或任何替代方法,例如可能将地图条件映射到带参数的委托?

1 个答案:

答案 0 :(得分:2)

以下是使用字符串通过Attributes进行用户访问以确定他们有权访问的内容的示例。这是使用Action / Controller来确定访问权限,但您可以根据需要修改它。

使用[AuthoriseByRole]

装饰控制器

首先是属性

namespace PubManager.Authorisation
{
    public class AuthoriseByRoleAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var isAuthorized = base.AuthorizeCore(httpContext);

            if (!isAuthorized && httpContext.Request.IsAjaxRequest())
            {
                httpContext.Response.StatusCode = 401;
                httpContext.Response.End();
            }

            if (isAuthorized)
            {
                var request = httpContext.Request;
                var r = request.RequestContext.RouteData.Values["r"]
                    ?? request["r"];
                var currentUser = (UserModel) HttpContext.Current.Session["user"];
                if (currentUser == null)
                {
                    currentUser = HttpContext.Current.User.GetWebUser();
                }
                var rd = httpContext.Request.RequestContext.RouteData;
                string currentAction = rd.GetRequiredString("action");
                string currentController = rd.GetRequiredString("controller");
                if (currentUser.HasAccess(currentController, currentAction))
                    return true;

            }
            httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            return false;
        }
    }
}

然后用于确定访问的UserModel:

namespace PubManager.Domain.Users
{
    public class UserModel
    {
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Title { get; set; }
        [Required]
        [DisplayName("Forename")]
        public string FirstName { get; set; }
        [Required]
        public string Surname { get; set; }
        [Required]
        [DisplayName("Company name")]
        public DateTime? LastLogin { get; set; }
        public bool LockedOut { get; set; }
        public DateTime? LockedOutUntil { get; set; }
        public bool IsGlobalAdmin { get; set; }
        public bool? IsSystemUser { get; set; }
        public IEnumerable<RoleModel> Roles { get; set; }

        public bool HasAccess(string controller, string view)
        {
            if (IsGlobalAdmin || IsSystemUser.Value)
            {
                return true;
            }
            var isAuthorized = false;

            if (!Roles.Any())
                return false;

            foreach (var role in Roles)
            {
                if (role.PageToRoles == null)
                    return false;

                foreach (var pg in role.PageToRoles)
                {
                    if (pg.RolePage.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase) && (pg.RolePage.View.Equals(view, StringComparison.InvariantCultureIgnoreCase) || pg.RolePage.View.Equals("*")))
                        isAuthorized = true;
                }
            }
            return isAuthorized;
        }
    }
}

最后GetWebUser类来获取用户

namespace PubManager.Domain.Users
{
    public static class SecurityExtensions
    {
        public static string Name(this IPrincipal user)
        {
            return user.Identity.Name;
        }

        public static UserModel GetWebUser(this IPrincipal principal)
        {
            if (principal == null)
                return new UserModel();

            var db = new DataContext();

            var user = (from usr in db.Users
                        where usr.UserName == principal.Identity.Name
                        select new UserModel
                        {
                            Title = usr.Person.Title,
                            UserName = usr.UserName,
                            FirstName = usr.Person.FirstName,
                            Surname = usr.Person.LastName,
                            Email = usr.Person.Email,
                            LockedOut = usr.LockedOut,
                            UserId = usr.UserId,
                            IsSystemUser = usr.IsSystemUser,
                            IsGlobalAdmin = usr.IsGlobalAdmin.Value,
                            PersonId = usr.PersonId,
                            Roles = from r in usr.UserToRoles
                                    select new RoleModel
                                    {
                                        RoleId = r.RoleId,
                                        PageToRoles = from ptr in r.Role.PageToRoles
                                                      select new PageToRoleModel
                                                      {
                                                          RolePage = new RolePageModel
                                                          {
                                                              Controller = ptr.RolePage.Controller,
                                                              View = ptr.RolePage.View
                                                          }
                                                      }
                                    }
                        }).FirstOrDefault();

            if (user != null)
            {                     
                    HttpContext.Current.Session["user"] = user;
            }

            return user;
        }
    }
}