#c# #generics #asp.net-mvc-5 #inversion-of-control #autofac
#c# #общие #asp.net-mvc-5 #инверсия управления #autofac
Вопрос:
Используя Autofac в качестве контейнера DI, я столкнулся с проблемой при реализации общего обработчика разрешений для проверки, имеет ли пользователь / участник доступ к определенному объекту.
Службы разрешений используют следующий общий интерфейс:
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
}
Веб-приложение находится в 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;
}
}
Проблема в том, что я не могу понять, как вызвать правильную реализацию IClaimsPrincipalPermission из статического метода checkAccess в классе ClaimsAuthorization .
Я не смог понять, как внедрить правильный экземпляр IClaimsPrincipalPermission в атрибут ClaimsAuthorizeAttribute (исследования заставили меня поверить, что это невозможно) из контроллера, и казалось, что моим единственным вариантом было разрешить зависимость из класса ClaimsAthorization . Поэтому я попытался разрешить зависимость с помощью DependencyResolver.Текущий.GetService и создание PermissionExecutor, который реализовал IPermissionExecutor. Чтобы больше не расширять этот вопрос, я не буду включать их здесь. Каков правильный подход к решению этой проблемы?