Psar Tak
Psar Tak

Reputation: 702

best way to filter rows by permission in Entity Framework

In my project I have some Post like as News , Article , Announcement and ...

each post have Permission , for example News post by Id 1 just admin users can that and ...

I should show post by user roles if Login .

to do this I trye some way :

way 1: I Add a Extension Method to filter News,Article , ... Like this

public static class EfExtensionMethods
{
   public  IEnumerable<News> Filter( IDbSet<News> dbset) 
   {
      return (dbset.Where(...));
   }
}

way 2: I add a Method to Service Layer for Filter rows , Like this:

public void FilterNews(IEnumerable<News> newsList)
{
   var roles = _currentUserService.GetCurrentUserRoles();
   if (roles.Count == 0)
   {
      newsList = newsList.Where(...).ToList();
   }
   else
   {
      newsList = newsList.Where(...).ToList();
   }
}

and everywhere I need just Pass List of NewsList to this Method to filter . witch one is beset ?

Is any best way ? I want a way that reuseable and dont copy for each class

Upvotes: 2

Views: 1659

Answers (2)

Alexander Derck
Alexander Derck

Reputation: 14498

You should make a static class with static Expressions, those you can use in your query and then it filters on the database (now you are fetching all rows from database and throwing away the ones you don't need which is a waste):

partial class News
{
    public static class Q
    {
        public static Expression<Func<News,bool>> HasPermission(int permissionID)
        {
            return expr => expr.PermissionID == permissionID
        }
     }
 }

Then you can do a query like this for example:

db.News.Where(News.Q.HasPermission(1)).ToList();

And you will fetch only the rows from the News table where the permission equals '1'. I don't really know how exactly your permissions are stored, but I think you get the idea :)

Edit: with generics, I think the simplest is to make your models inherit from Permissionbase class or something:

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

Without baseclass it should be possible too by building your Expression on the run:

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

Just make sure the propertyname is correct in all your models then obviously, or you can pass the propertyname to the method with a string.

Upvotes: 3

Anton Vorobyev
Anton Vorobyev

Reputation: 58

As I assume you're talking about row-level security. It's quite a complex task. There are several approaches to do it.

For MSSQL try to have a look at MSDN Security Blog about RLS

Upvotes: 1

Related Questions