将字符串规则映射到 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)方法中,我将从 DB 加载此操作键的所有用户相关规则,并决定是否应允许用户。

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

用户必须是"客户"组的成员,并且产品不得属于"奶酪"类型或

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

如何将此类条件存储为每个规则的字符串,然后从中生成 LINQ 表达式?

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

对于存储字符串的便捷方法,任何想法都非常受欢迎,可以在运行时将其转换为 LINQ 表达式或任何替代方法,例如使用参数将条件映射到委托?

下面是用户使用字符串通过属性进行访问的示例,以确定他们有权访问的内容。这是使用操作/控制器来确定访问权限,但您可以针对所需的任何字符串对其进行修改。

使用 [授权角色] 装饰控制器

首先是属性

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

然后,用于确定访问权限的用户模型:

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

相关内容

最新更新