簡體   English   中英

使用ASP.NET Identity和Autofac OWIN集成進行授權

[英]Authorization with ASP.NET Identity & Autofac OWIN integration

(此問題的底部添加了更新)

我有一個Web應用程序,它使用MVC5和WebAPI2以及用於DI的Autofac。 該應用程序使用ASP.NET身份和oAuth承載令牌,雖然后者可能不重要。 這一切都運行得很好,但此時我需要在整個OWIN管道以及我的應用程序的其余部分共享我注入的服務的相同實例,因此我正在嘗試為MVC和Web設置Autofac的OWIN集成API。 我似乎很接近 - 除了ApiControllers AuthorizeAttibutes之外,一切似乎都ApiControllers oAuth進程成功完成,我最終使用不記名令牌登錄,但隨后嘗試使用WebAPI控制器/操作上的所述令牌進行授權失敗。

具體來說,在System.Web.Http.AuthorizeAttributeIsAuthorized方法中, IPrincipal.Identity似乎沒有正確實例化,因為它沒有相應的聲明,並且IsAuthenticated屬性始終為false。 Autofac的開發人員表示該屬性應該與OWIN集成一起使用 ,即使該代碼使用的GlobalConfiguration 不適用於OWIN集成 我已經看到了刪除config.SuppressDefaultHostAuthentication()這里這里 )的多個建議,雖然這是不可取的,但我已經嘗試了絕望但是沒有用 - 對於我的特定配置,這會導致IPrincipal返回null 。 我還嘗試修改一個比我自己更簡單的示例項目 ,以便在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();
    }
}

我認為這涵蓋了它,但我很樂意根據要求發布額外的代碼。

UPDATE

所以根據jumuro的回答 ,我按照建議更改了我的注冊順序。 但是,這只是將完全相同的問題從Web API授權轉移到MVC授權。 由於我在更新之前有MVC auth工作,我最終嘗試在管道中注冊兩次auth,如下所示:

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

這是有效的,但我真的不能說我理解為什么,我無法想象這樣做兩次是好的。 所以現在我有了新的問題:

  1. 有意義的是,WebAPI首先需要在管道中注冊Auth,但為什么MVC要求我最后注冊Auth呢?
  2. 如何清理它並避免兩次調用ConfigureAuth

您必須以正確的順序將中間件添加到應用程序管道。 在MVC和Web Api中間件處理請求之前,必須驗證承載令牌。

Configuration()方法中嘗試此順序:

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

我希望它有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM