gpt4 book ai didi

c# - 通用权限管理器模式

转载 作者:行者123 更新时间:2023-11-30 12:45:02 24 4
gpt4 key购买 nike

我想做的是创建一个带有静态方法的类来管理不同用户类型对某些类型资源(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 定义相同的方法...除了要调用的方法名称外完全相同。

我要问的是:是否有更好的方法来以更面向对象的方式定义我的想法?

最佳答案

我已经实现了一个更好的解决方案,可能对某些人来说很有趣。

这是一个“我可以访问吗?”的界面。查询:

public interface ICanAccessQuery<TAccount, TEntity>
where TAccount : IAccountOwner
where TEntity : IStoredEntity
{
bool CanView(TAccount user, TEntity entity);
bool CanEdit(TAccount user, TEntity entity);
}

我的实体现在实现了一个空接口(interface) 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, TEntity>(user as Teacher, ability, entity);
}
else if (user is TrainingCenter)
{
return Can<TrainingCenter, TEntity>(user as TrainingCenter, ability, 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, TEntity>(TAccount user, 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 Controller 中的使用示例:

public ActionResult Details(long? id)
{
if (!id.HasValue)
return new EmptyResult();

if (!AuthorizationProvider.CanI<CourseReport>(AuthorizationProvider.Abilities.View, id.Value))
return RedirectToAccessDenied();

// etc.
}

关于c# - 通用权限管理器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25863459/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com