【问题标题】:asp.net MVC5 - Dependency Injection and AuthorizeAttributeasp.net MVC5 - 依赖注入和 AuthorizeAttribute
【发布时间】:2015-10-20 01:23:46
【问题描述】:

我为我的问题寻找了很长时间的解决方案。我有一个自定义 AuthorizeAttribute,它需要依赖于可以访问 DbContext 的“服务”。 遗憾的是,依赖注入在自定义 AuthorizeAttribute 中不起作用,并且始终为空。

我想出了一个(对我而言)可接受的解决方案。现在我想知道我的解决方案是否会导致无法预料的行为?

Global.asax.cs

 CustomAuthorizeAttribute.AuthorizeServiceFactory = () => unityContainer.Resolve<AuthorizeService>();

CustomAuthorizeAttribute.cs

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        public static Func<AuthorizeService> AuthorizeServiceFactory { get; set; }

        public Privilege Privilege { get; set; }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool authorized = base.AuthorizeCore(httpContext);
            if (!authorized)
            {
                return false;
            }

            return AuthorizeServiceFactory().AuthorizeCore(httpContext, Privilege);
        }
    }

AuthorizeService.cs

public class AuthorizeService
{
    [Dependency]
    public UserService UserService { private get; set; }

    public bool AuthorizeCore(HttpContextBase httpContext, Privilege privilege)
    {
        ApplicationUser user = UserService.FindByName(httpContext.User.Identity.Name);
        return UserService.UserHasPrivilege(user.Id, privilege.ToString());
    }
}

这是一个可接受的解决方案吗?我将来会遇到令人讨厌的问题,还是有更好的方法在自定义 AuthorizeAttribute 中使用依赖注入?

【问题讨论】:

    标签: c# entity-framework dependency-injection asp.net-mvc-5 authorize-attribute


    【解决方案1】:

    我有一个自定义 AuthorizeAttribute 需要依赖于 有权访问 DbContext 的“服务”。可悲的是依赖 注入在自定义 AuthorizeAttribute 中不起作用,并且始终 空。

    System.Web.Mvc 命名空间中IControllerFactory 的实现会为您的控制器 创建用于Web 请求的实例。 Controller Factory 使用System.Web.Mvc.DependencyResolver 来解决每个控制器中的依赖关系。

    但是,MVC pipeline 中的 ActionFilters/Attributes 不是从控制器工厂创建的,因此无法使用 System.Web.Mvc.DependencyResolver 解决依赖关系。这就是为什么你的依赖总是null

    现在,System.Web.Mvc.DependencyResolverpublicstatic,因此您可以自己访问。

        public class AuthorizeService : AuthorizeAttribute
        {
            private UserService UserService
            {
                get
                {
                    return DependencyResolver.Current.GetService<UserService>();
                }
            }
    
            public bool AuthorizeCore(HttpContextBase httpContext, Privilege privilege)
            {
                ApplicationUser user = UserService.FindByName(httpContext.User.Identity.Name);
                return UserService.UserHasPrivilege(user.Id, privilege.ToString());
            }
        }
    

    假设您的UserService具有WebRequest的依赖范围,即它的生命周期是每个网络请求一个并与网络请求的HttpContext的生命周期相关联如果这是第一次为给定的 Web 请求解决了UserService,则这不会构造新的UserService

    【讨论】:

    • 我同意这个解决方案
    • 我遇到了同样的问题,上面的答案很有帮助。但是由于我使用的是Autofac,它们提供了一种通过提供程序autofaccn.readthedocs.io/en/latest/integration/…解决动作过滤器中的依赖关系的方法,但是我在使用上述提供程序时遇到的问题是,我的UserService依赖于DbContext ,它会抛出一个错误“操作无法完成,因为 DbContext 已被处理错误 r”只有当我在让上一个请求完成之前点击浏览器刷新按钮时
    【解决方案2】:

    在 ASP.NET Core 中,您可以轻松地请求服务,如下所示:

    public class CustomAuthAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        public async void OnAuthorization(AuthorizationFilterContext context)
        {
            // var user = context.HttpContext.User;
    
            // if (!user.Identity.IsAuthenticated)
            // {
            //     context.Result = new UnauthorizedResult();
            //     return;
            // }
    
            var userService = context.HttpContext.RequestServices.GetService(typeof(UserService)) as UserService;
        }
    }
    

    【讨论】:

    • 问题不是asp net core。架构上的差异太深了。
    • 这就是我提到“ASP.NET Core”的原因。我在这里添加了这个答案,因为我猜像我这样的很多人最终会在“ASP.NET Core”中遇到类似的问题:-)
    • 谢谢马吉德。我想知道以这种方式获得服务有什么缺点吗?如果您能对这里发生的事情有所了解,我将不胜感激。即使结果是我想要的,我也没有信心在不理解的情况下使用它。
    • @Lukas 这里发生的事情是RequestServicesIServiceProvider 类型的属性,它自动配置并设置为IServiceProvider,该IServiceProvider 是从IServiceCollection 中定义和注册的DI 成立。 (用于 ASP.NET Core 的 Startup.cs)。
    【解决方案3】:

    你也可以试试这个:

    ASP.NET Web API and dependencies in request scope

    public override void OnAuthorization(HttpActionContext filterContext)
    {
        var requestScope = filterContext.Request.GetDependencyScope();
        _userService = requestScope.GetService(typeof(IUserService)) as IUserService;
    }
    
    //
    // Summary:
    //     Retrieves the System.Web.Http.Dependencies.IDependencyScope for the given request
    //     or null if not available.
    //
    // Parameters:
    //   request:
    //     The HTTP request.
    //
    // Returns:
    //     The System.Web.Http.Dependencies.IDependencyScope for the given request or null
    //     if not available.
    public static IDependencyScope GetDependencyScope(this HttpRequestMessage request);
    

    【讨论】:

      猜你喜欢
      • 2015-04-22
      • 1970-01-01
      • 2014-05-11
      • 2010-10-27
      • 2010-12-05
      • 2011-03-18
      • 1970-01-01
      • 1970-01-01
      • 2014-07-11
      相关资源
      最近更新 更多