在 Entity Framework 中按权限过滤行的最佳方式
best way to filter rows by permission in Entity Framework
在我的项目中我有一些 Post 像 News
, Article
, Announcement
和 ...
每个 post 都有权限,例如 Id 1
的新闻 post 只有管理员用户可以,并且...
如果登录,我应该按用户角色显示 post。
为此我尝试了一些方法:
方式一:
我添加了一个扩展方法来过滤 News,Article , ... Like this
public static class EfExtensionMethods
{
public IEnumerable<News> Filter( IDbSet<News> dbset)
{
return (dbset.Where(...));
}
}
方式 2:
我为过滤行添加了一个方法到服务层,像这样:
public void FilterNews(IEnumerable<News> newsList)
{
var roles = _currentUserService.GetCurrentUserRoles();
if (roles.Count == 0)
{
newsList = newsList.Where(...).ToList();
}
else
{
newsList = newsList.Where(...).ToList();
}
}
在任何地方,我只需要将 NewsList 的列表传递给此方法进行过滤。
一个人被困?
有什么好的方法吗?
我想要一种可重复使用且不为每个 class
复制的方法
我假设您在谈论行级安全性。这是一项相当复杂的任务。
有几种方法可以做到这一点。
对于 MSSQL,请尝试查看 MSDN Security Blog about RLS
你应该用静态 Expressions
制作一个静态 class,那些你可以在你的查询中使用然后它在数据库上过滤(现在你正在从数据库中获取所有行并丢弃那些你不需要的,这是一种浪费):
partial class News
{
public static class Q
{
public static Expression<Func<News,bool>> HasPermission(int permissionID)
{
return expr => expr.PermissionID == permissionID
}
}
}
然后你可以这样查询,例如:
db.News.Where(News.Q.HasPermission(1)).ToList();
并且您将仅从 News
table 中获取权限等于“1”的行。我真的不知道你的权限是如何存储的,但我想你明白了:)
编辑:对于泛型,我认为最简单的方法是让您的模型继承自 Permissionbase class 或其他东西:
public abstract class PermissionBase
{
public int PermissionID {get; set;}
}
public static class QueryExtensions
{
public static Expression<Func<T,bool>> HasPermission<T>(int permissionID) where T: PermissionBase
{
return expr => expr.PermissionID == permissionID
}
}
没有 baseclass 也应该可以通过在 运行 上构建 Expression
:
public static Expression<Func<T, bool>> HasPermission<T>(int PermissionID) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
System.Reflection.PropertyInfo pi = typeof(T).GetProperty("PermissionID");
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(PermissionID);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);
}
显然,只需确保所有模型中的属性名称都是正确的,或者您可以将属性名称传递给带有字符串的方法。
在我的项目中我有一些 Post 像 News
, Article
, Announcement
和 ...
每个 post 都有权限,例如 Id 1
的新闻 post 只有管理员用户可以,并且...
如果登录,我应该按用户角色显示 post。
为此我尝试了一些方法:
方式一: 我添加了一个扩展方法来过滤 News,Article , ... Like this
public static class EfExtensionMethods
{
public IEnumerable<News> Filter( IDbSet<News> dbset)
{
return (dbset.Where(...));
}
}
方式 2: 我为过滤行添加了一个方法到服务层,像这样:
public void FilterNews(IEnumerable<News> newsList)
{
var roles = _currentUserService.GetCurrentUserRoles();
if (roles.Count == 0)
{
newsList = newsList.Where(...).ToList();
}
else
{
newsList = newsList.Where(...).ToList();
}
}
在任何地方,我只需要将 NewsList 的列表传递给此方法进行过滤。 一个人被困?
有什么好的方法吗? 我想要一种可重复使用且不为每个 class
复制的方法我假设您在谈论行级安全性。这是一项相当复杂的任务。 有几种方法可以做到这一点。
对于 MSSQL,请尝试查看 MSDN Security Blog about RLS
你应该用静态 Expressions
制作一个静态 class,那些你可以在你的查询中使用然后它在数据库上过滤(现在你正在从数据库中获取所有行并丢弃那些你不需要的,这是一种浪费):
partial class News
{
public static class Q
{
public static Expression<Func<News,bool>> HasPermission(int permissionID)
{
return expr => expr.PermissionID == permissionID
}
}
}
然后你可以这样查询,例如:
db.News.Where(News.Q.HasPermission(1)).ToList();
并且您将仅从 News
table 中获取权限等于“1”的行。我真的不知道你的权限是如何存储的,但我想你明白了:)
编辑:对于泛型,我认为最简单的方法是让您的模型继承自 Permissionbase class 或其他东西:
public abstract class PermissionBase
{
public int PermissionID {get; set;}
}
public static class QueryExtensions
{
public static Expression<Func<T,bool>> HasPermission<T>(int permissionID) where T: PermissionBase
{
return expr => expr.PermissionID == permissionID
}
}
没有 baseclass 也应该可以通过在 运行 上构建 Expression
:
public static Expression<Func<T, bool>> HasPermission<T>(int PermissionID) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
System.Reflection.PropertyInfo pi = typeof(T).GetProperty("PermissionID");
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(PermissionID);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);
}
显然,只需确保所有模型中的属性名称都是正确的,或者您可以将属性名称传递给带有字符串的方法。