c# – 通用权限管理器模式
发布时间:2020-12-15 22:08:05 所属栏目:百科 来源:网络整理
导读:我要做的是创建一个使用静态方法的类来管理某些类型资源(NHibernate实体对象)上不同用户类型的权限.具体来说,我想针对对象id检查当前主体(在asp.net MVC项目中),以查看他是否可以查看或编辑实体.我想到的签名如下: PermissionManager.CanViewTEntity(object
我要做的是创建一个使用静态方法的类来管理某些类型资源(NHibernate实体对象)上不同用户类型的权限.具体来说,我想针对对象id检查当前主体(在asp.net MVC项目中),以查看他是否可以查看或编辑实体.我想到的签名如下:
PermissionManager.CanView<TEntity>(object id); 到现在为止我已经完成了以下步骤: 1)这样的界面: public interface ICanAccessQuery<TAccount,TEntity> where TAccount : IAccountOwner { bool CanView(TAccount user,object entityKey); bool CanEdit(TAccount user,object entityKey); } 2)像这样的一些实现: public class TeacherCanAccessCourseReportsQuery : ICanAccessQuery<Teacher,CourseReport> { public bool CanView(Teacher user,object entityKey) { var predicate = PredicateBuilder.Create<CourseReport>(x => x.Id == (long)entityKey); var conditions = PredicateBuilder.Create<CourseReport>(x => x.Teacher.Id == user.Id); conditions = conditions.Or(x => x.Teacher.Tutor.Id == user.Id); conditions = conditions.Or(x => x.CoachingTeachers.Any(t => t.Id == user.Id)); predicate = predicate.And(conditions); return RepositoryProvider.Get<CourseReport>().Count(predicate) > 0; } public bool CanEdit(Teacher user,object entityKey) { // similar implementation } } 3)我的PermissionManager类中的静态Configure()方法,在Global.asax中调用: public static IDictionary<string,object> _permissions = new Dictionary<string,object>(); public static void Configure() { _permissions.Add(typeof(Teacher).Name + typeof(CourseReport).Name,new TeacherCanAccessCourseReportsQuery()); } 4)在PermissionManager类中: public static bool CanView<TEntity>(object primaryKey,params string[] enabledRoles) { var accounts = RepositoryProvider.Get<Account,AccountRepository>(); var principal = Thread.CurrentPrincipal as MyCustomPrincipal; if (enabledRoles.Any(r => principal.IsInRole(r))) return true; IAccountOwner user = accounts.GetUser(principal.AccountId); var can = false; var @switch = new Dictionary<Type,Action> { { typeof(Teacher),() => can = CanView<Teacher,TEntity>(user as Teacher,primaryKey) },{ typeof(TrainingCenter),() => can = CanView<TrainingCenter,TEntity>(user as TrainingCenter,primaryKey) } }; @switch[user.GetType()](); return can; } private static bool CanView<TAccount,TEntity>(TAccount user,object primaryKey) where TAccount : IAccountOwner { var key = typeof(TAccount).Name + typeof(TEntity).Name; if (_permissions.ContainsKey(key)) { return (((ICanAccessQuery<TAccount,TEntity>)_permissions[key]).CanView(user,primaryKey); } return false; } 将为CanEdit定义相同的方法…除了要调用的方法名称之外完全相同. 我要问的是:是否有更好的方法来定义我的想法,以更多的OOP方式? 解决方法
我已经实现了一个更好的解决方案,可能对某些人来说很有趣.
这是“我可以访问吗?”的界面.查询: public interface ICanAccessQuery<TAccount,TEntity> where TAccount : IAccountOwner where TEntity : IStoredEntity { bool CanView(TAccount user,TEntity entity); bool CanEdit(TAccount user,TEntity entity); } 我的实体现在实现了一个空接口IStoredEntity来制作约束. 这是一个实施的例子: public class TeacherCanAccessOrdersQuery : ICanAccessQuery<Teacher,Order> { public bool CanView(Teacher user,Order entity) { var predicate = PredicateBuilder.Create<Order>(x => x.Id == entity.Id && x => x.Account.Id == user.Account.Id); return RepositoryProvider.Get<Order>().Count(predicate) > 0; } public bool CanEdit(Teacher user,Order entity) { // similar implementation } } 最后,我的新AuthorizationProvider类(从PermissionManager更改名称,不喜欢它): public class AuthorizationProvider { public enum Abilities { View,Edit }; private static IDictionary<string,object> _authorizations = new Dictionary<string,object>(); // this method should be called at application bootstrap,such as Global.asax in an asp.net app public static void Configure() { _authorizations.Add(typeof(Teacher).Name + typeof(CourseReport).Name,new TeacherCanAccessCourseReportsQuery()); _authorizations.Add(typeof(Teacher).Name + typeof(Order).Name,new TeacherCanAccessOrdersQuery()); // other rules user type-entity type } // Can I view entity with primary key X? public static bool CanI<TEntity>(Abilities ability,object entityKey) where TEntity : IStoredEntity { TEntity entity = RepositoryProvider.Get<TEntity>().Load(entityKey); return CanI<TEntity>(ability,entity,AccountRoles.Admin); } // Can I view entity (and if I have a specific role,I surely can)? public static bool CanI<TEntity>(Abilities ability,TEntity entity,params string[] authorizedRoles) where TEntity : IStoredEntity { var principal = Thread.CurrentPrincipal as MyCustomPrincipal; if (authorizedRoles.Any(r => principal.IsInRole(r))) return true; var user = RepositoryProvider.Get<Account,AccountRepository>().GetUser(principal.AccountId); // my system has only two types of users if (user is Teacher) { return Can<Teacher,ability,entity); } else if (user is TrainingCenter) { return Can<TrainingCenter,entity); } return false; } /// Can user X (view|edit) entity Y? /// With some reflection I call the needed method. In this way I can add "abilities" to my ICanAccessQuery /// interface and its implementations without altering this class. public static bool Can<TAccount,Abilities ability,TEntity entity) where TAccount : IAccountOwner where TEntity : IStoredEntity { var key = typeof(TAccount).Name + typeof(TEntity).Name; if (_authorizations.ContainsKey(key)) { var query = (ICanAccessQuery<TAccount,TEntity>)_authorizations[key]; string methodName = "Can" + ability.ToString(); var method = typeof(ICanAccessQuery<TAccount,TEntity>).GetMethod(methodName); return (bool)method.Invoke(query,new object[] { user,entity }); } return false; } } 在asp.net mvc控制器中使用的一个示例: public ActionResult Details(long? id) { if (!id.HasValue) return new EmptyResult(); if (!AuthorizationProvider.CanI<CourseReport>(AuthorizationProvider.Abilities.View,id.Value)) return RedirectToAccessDenied(); // etc. } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |