2

我有一个组件可以检查当前登录的用户是否可以访问控制器的操作。

public class ControllerAccessChecker : IControllerAccessChecker
{
    ILifetimeScope _scope;

    public ControllerAccessChecker(ILifetimeScope scope)
    {
        _scope = scope;
    }

    public bool IsAccessible<TController>(Expression<Action<TController>> action, RequestContext requestContext) where TController : Controller
    {
        var actionName = GetActionName(action);
        var result = false;

        using (var childScope = _scope.BeginLifetimeScope())
        {
            var controller = childScope.Resolve<TController>(); 
            result = HasActionPermission(requestContext, actionName, controller);
        }
        return result;
    }

    private static string GetActionName(LambdaExpression actionExpression)
    {
        object operand;
        if (actionExpression.Body as UnaryExpression != null)
        {
            operand = ((UnaryExpression)actionExpression.Body).Operand;
        }
        else
        {
            operand = actionExpression.Body;
        }
        MethodCallExpression methodCallExpression = (MethodCallExpression)operand;
        return methodCallExpression.Method.Name;
    }

    private static bool HasActionPermission(RequestContext requestContext, string actionName, ControllerBase controller)
    {
        var controllerContext = new ControllerContext(requestContext, controller);

        var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());

        var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);

        return ActionIsAuthorized(controllerContext, actionDescriptor);
    }


    private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        if (actionDescriptor == null)
            return false;

        AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);

        foreach (Filter authFilter in FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor).Where(x => x.Instance is IAuthorizationFilter))
        {
            ((IAuthorizationFilter)authFilter.Instance).OnAuthorization(authContext);

            if (authContext.Result != null)
                return false;
        }

        return true;
    }
}

如您所见,我正在注入ILifetimeScope构造函数,但我不确定这是否是一种好习惯。另外我不确定我是否在IsAccessible方法中做正确的事情。这种 Autofac 的作用域层次方法让我很困惑。

我在考虑某种控制器的抽象工厂,但用 Autofac 实现似乎并不容易。IIndex<,>我在这里找到了一些关于使用和注册的文章和答案,.Keyed()但我不认为这真的是在这种情况下应该使用的。我的意思是我知道我需要什么类型,所以只要提出要求就应该很容易。

4

1 回答 1

1

您可以使用而不是注入生命周期范围AutofacDependencyResolver.Current.RequestLifetimeScope- 除非您在 Web 上下文之外使用它,否则我可能会使用它。

关于这个设计的一件事:IsAccessible你正在解析实际的控制器,这也意味着你正在解析和实例化它的所有依赖项,一直到整个链条。如果您在菜单系统中执行此操作,或者在某个地方对每个请求都执行大量此类操作,那么这就是很多控制器(和控制器依赖项)。而且,如果您的控制器依赖项是数据库连接或 WCF 服务代理……那么,仅检查可访问性可能会变得非常昂贵。需要考虑的事情。

于 2013-01-25T16:28:40.320 回答