使用Autofac作为DI容器,我遇到了一个实现通用权限处理程序的问题,用于检查User / Principal是否可以访问特定实体。
权限服务使用以下通用接口:
public interface IClaimsPrincipalPermission<in TPrincipal, in TAction, in TResource>
where TPrincipal : AppUserPrincipal
where TAction : BaseSecurity.Actions
where TResource : BaseSecurity.Resources
{
IdentityResult CheckAccess(SecurityAction secuirtyAction, TPrincipal principal, TAction action, TResource resource);
IdentityResult CheckAccess(SecurityAction secuirtyAction, TPrincipal principal, TAction action, TResource resource, string id);
}
示例实现将是:
internal class FruitClaimsPrincipalPermission
: IClaimsPrincipalPermission<AppUserPrincipal, UpdateAction, FruitResource>
{
private readonly IFruitRepository _fruitRepository;
public FruitClaimsPrincipalPermission(IFruitRepository fruitRepository)
{
if (fruitRepository == null)
throw new ArgumentNullException("fruitRepository");
_fruitRepository = fruitRepository;
}
#region Implementation of IClaimsPrincipalPermission<AppUserPrincipal, UpdateAction, FruitResource>
public IdentityResult CheckAccess(System.Security.Permissions.SecurityAction secuirtyAction, AppUserPrincipal principal, CreateAction action, FruitResource resource) {
if (principal == null || action == null || resource == null)
throw new ArgumentNullException();
if (!principal.Identity.IsAuthenticated)
return IdentityResult.Failed(SecurityResouces.Requires_Authentication);
if (!principal.IsSetupAdministrator)
return IdentityResult.Failed(SecurityResouces.Requires_Setup_Admin_Role);
return IdentityResult.Success;
}
public IdentityResult CheckAccess(System.Security.Permissions.SecurityAction secuirtyAction, AppUserPrincipal principal, CreateAction action, FruitResource resource, string id) {
if (principal == null || action == null || resource == null)
throw new ArgumentNullException();
if (!principal.Identity.IsAuthenticated)
return IdentityResult.Failed(SecurityResouces.Requires_Authentication);
if (!principal.IsSetupAdministrator)
return IdentityResult.Failed(SecurityResouces.Requires_Setup_Admin_Role);
var fruit = _fruitRepository.GetById(id);
if (fruit.AccountId != principal.AccountId)
return IdentityResult.Failed(SecurityResouces.Owner_Account_User_Mismatch);
return IdentityResult.Success;
}
#endregion
}
Web应用程序位于MVC 5和.Net 4.5中。我创建了一个自定义授权属性,用于装饰需要授权访问特定实体的任何控制器。 ResourceType 和 ActionType 都是代表授权请求中的资源和操作的枚举。
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
private readonly ResourceType[] _resources;
private readonly ActionType _action;
public ClaimsAuthorizeAttribute(ActionType action, params ResourceType[] resources)
{
_resources = resources;
_action = action;
}
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
var principal = new AppUserPrincipal(httpContext.User as ClaimsPrincipal);
var action = ActionRepository.FindActions(_action);
var resources = _resources.Select(ResourceRepository.FindResource).ToArray();
return ClaimsAuthorization.CheckAccess(action, resources.First(), principal, "", out result);
}
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
}
}
ClaimsAuthorization 是ClaimsAuthorizationManager的子类,它实现了一个静态CheckAccess方法。
public class ClaimsAuthorization : ClaimsAuthorizationManager
{
public static bool CheckAccess(Actions action, Resources resource, AppUserPrincipal principal, string entityId, out IdentityResult result)
{
result = DependencyResolver.Current.GetService<IPermissionExecutor>().CheckAccess(SecurityAction.Demand, principal, action, resource);
return result.Succeeded;
}
}
问题是我无法弄清楚如何从ClaimsAuthorization类中的静态CheckAccess方法调用 IClaimsPrincipalPermission 的正确实现。
我无法从控制器中找出如何将 IClaimsPrincipalPermission 的正确实例注入到ClaimsAuthorizeAttribute(研究让我相信它是不可能的),这似乎是我的唯一的选择是从ClaimsAthorization类中解析依赖项。因此,我尝试使用 DependencyResolver.Current.GetService 并创建实现 IPermissionExecutor 的 PermissionExecutor 来解决依赖关系。为了不再延长这个问题,我不会在这里包括这些问题。解决这个问题的正确方法是什么?