【问题标题】:Authorization with ASP.NET Identity & Autofac OWIN integration使用 ASP.NET Identity 和 Autofac OWIN 集成进行授权
【发布时间】:2023-03-07 02:33:01
【问题描述】:

(已在此问题的底部添加了更新)

我有一个 Web 应用程序,它同时使用 MVC5 和 WebAPI2 以及 Autofac for DI。该应用程序使用 ASP.NET 身份和 oAuth 持有者令牌,尽管后者可能不是重点。这一切都运行良好,但此时我需要在整个 OWIN 管道以及我的应用程序的其余部分共享我注入的服务的相同实例,因此我正在尝试为 MVC 和 Web 设置 Autofac 的 OWIN 集成API。我似乎很接近——除了ApiControllers 上的AuthorizeAttibutes 之外,一切似乎都正常。 oAuth 过程成功完成,我最终使用不记名令牌登录,但随后尝试在 WebAPI 控制器/操作上使用所述令牌进行授权失败。

具体来说,在System.Web.Http.AuthorizeAttributeIsAuthorized 方法中,IPrincipal.Identity 似乎没有被正确实例化,因为它没有适当的声明并且IsAuthenticated 属性始终为假。 Autofac 的开发人员指出this attribute should work with the OWIN integrations,即使该代码使用GlobalConfigurationwhich is not advisable for the OWIN integrations。我已经看到了多个删除config.SuppressDefaultHostAuthentication()herehere)的建议,虽然这不是可取的,但我出于绝望而尝试过但无济于事 - 对于我的特定配置,这会导致 IPrincipal 回来为空。我还尝试修改a much simpler example project,而不是我自己的,以便在WebAPI 控制器上使用AuthorizeAttribute,但也没有成功。在这一点上,我没有东西可以尝试,我们将不胜感激。

这是我的 Startup.cs:

[assembly: OwinStartup(typeof (Startup))]
namespace Project.Web
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var builder = new ContainerBuilder();
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            var config = new HttpConfiguration();
            builder.RegisterHttpRequestMessage(config);
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            RegisterGeneralTypes(builder);
            var container = builder.Build();
            WebApiConfig.Register(config);
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            WebApiFilterConfig.RegisterGlobalFilters(config.Filters);

            app.UseAutofacMiddleware(container);
            app.UseAutofacWebApi(config);
            app.UseAutofacMvc();
            app.UseWebApi(config);

            ConfigureAuth(app);
        }

        private static void RegisterGeneralTypes(ContainerBuilder builder)
        {
            builder.Register(c => new DomainModelContext())
                .AsSelf()
                .InstancePerRequest();

            builder.Register(c => HttpContext.Current.User.Identity)
                .As(typeof (IIdentity));

            builder.RegisterType<EmailService>()
                .AsImplementedInterfaces()
                .InstancePerRequest();

            builder.Register(c => new IdentityFactoryOptions<DomainUserManager>
            {
                DataProtectionProvider = DataProtectionProvider
            }).InstancePerRequest();

            builder.RegisterType<DomainUserManager>()
                .AsSelf()
                .UsingConstructor(typeof (IIdentityMessageService),
                    typeof (IdentityFactoryOptions<DomainUserManager>),
                    typeof (CustomUserStore))
                .InstancePerRequest();

            builder.RegisterType<CustomUserStore>()
                .AsImplementedInterfaces()
                .AsSelf()
                .InstancePerRequest();

            builder.Register(c => HttpContext.Current.GetOwinContext().Authentication)
                .As<IAuthenticationManager>();
        }
    }
}

还有我的 Startup.Auth.cs:

public partial class Startup
{
    internal static IDataProtectionProvider DataProtectionProvider;
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
    public static string PublicClientId { get; private set; }

    public void ConfigureAuth(IAppBuilder app)
    {
        var onValidateIdentity = SecurityStampValidator
            .OnValidateIdentity<DomainUserManager, DomainUser, int>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentityCallback: (manager, user) =>
                    user.GenerateUserIdentityAsync(manager, CookieAuthenticationDefaults.AuthenticationType),
                getUserIdCallback: id => id.GetUserId<int>());

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            LoginPath = new PathString("/account/login"),

            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = onValidateIdentity
            }
        });
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/v1/account/externallogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        DataProtectionProvider = app.GetDataProtectionProvider();
    }
}

我认为这涵盖了它,但我很乐意应要求发布其他代码。

更新

因此,根据jumuro's answer,我按照建议更改了注册顺序。但是,这只是将完全相同的问题从 Web API 授权转移到 MVC 授权。由于我在更新之前有 MVC 身份验证工作,因此我最终尝试在管道中注册身份验证两次,如下所示:

app.UseAutofacMiddleware(container);
ConfigureAuth(app);
app.UseAutofacWebApi(config);
app.UseAutofacMvc();
app.UseWebApi(config);
ConfigureAuth(app);

这行得通,但我真的不能说我明白为什么,我无法想象这样做两次是件好事。所以现在我有新的问题:

  1. WebAPI 需要在 管道优先,但为什么 MVC 要我注册 验证最后
  2. 我怎样才能清理它并避免两次调用ConfigureAuth

【问题讨论】:

  • 那么会发生什么?你有错误吗?你能发布错误信息吗?
  • @NightOwl888 就像我说的那样,IPrincipal.Identity.IsAuthenticated 总是返回为假,因此授权失败并向客户端返回 404 响应。什么都没有发生,IPrincipal 似乎没有被正确实例化。就细节而言,它的行为几乎与links I posted above 之一完全相同。但是,在我的情况下,删除 config.SuppressDefaultHostAuthentication() 会导致 IPrincipal 变为 null。

标签: asp.net asp.net-mvc asp.net-web-api owin autofac


【解决方案1】:

您必须以正确的顺序将中间件添加到应用程序管道。在 MVC 和 Web Api 中间件处理请求之前,必须验证不记名令牌。

在您的 Configuration() 方法中尝试此顺序:

public void Configuration(IAppBuilder app)
{
    ...
    app.UseAutofacMiddleware(container);
    ConfigureAuth(app);
    app.UseAutofacMvc();
    app.UseWebApi(config);
    app.UseAutofacWebApi(config);
    ...
}

希望对你有帮助。

【讨论】:

  • 如此接近!这修复了 WebAPI 中的问题,但会导致完全相同的问题出现在 MVC 中。
  • 在添加 Autofac 之前,相同的 ConfigureAuth() 方法是否适用于 MVC 和 Web Api?
  • 在为 Autofac 添加 OWIN 集成之前,相同的 ConfigureAuth() 正在使用 Autofac 为 MVC 和 Web API 工作。 OWIN 集成是导致手头问题的原因。
  • 您可能需要深入了解生命周期以了解此行为。在这种情况发生之前,为了避免重复代码,您可以尝试将您的 ConfigureAuth() 方法拆分为 ConfigureAuthMvc()ConfigureAuthWebApi() 并按您需要的顺序调用每个方法。
  • 如果你发现了,我希望你能分享对行为的解释,谢谢。
猜你喜欢
  • 2017-03-07
  • 1970-01-01
  • 2018-03-14
  • 2017-01-19
  • 1970-01-01
  • 2014-08-15
  • 1970-01-01
  • 2017-09-26
  • 2015-11-06
相关资源
最近更新 更多