2016-06-15 69 views
4

(更新已經在這個問題的底部添加)授權使用ASP.NET身份和Autofac OWIN整合

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

具體來說,在System.Web.Http.AuthorizeAttributeIsAuthorized方法,IPrincipal.Identity似乎還沒有被正確的,因爲它不具備相應的索賠實例化和IsAuthenticated屬性始終爲false。 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(); 
    } 
} 

我認爲,涵蓋了,但我會應要求樂意交額外的代碼。

UPDATE

因此,基於jumuro's answer,我改變了我註冊的順序推薦。但是,這只是將完全相同的問題從Web API授權轉移到MVC授權。因爲我更新之前有MVC權威性的工作,我最終試圖在管道註冊AUTH兩次如下:

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

這工作,但我真的不能說,我明白爲什麼我不能想象這樣做兩次很好。所以現在我有新的問題:

  1. 這是有道理的WebAPI需要驗證在 管道註冊第一,但爲什麼在世界上確實MVC要我註冊 驗證最後
  2. 我該如何清理並避免兩次撥打ConfigureAuth
+0

那麼會發生什麼?你有錯誤嗎?你能發佈錯誤信息嗎? – NightOwl888

+0

@ NightOwl888就像我所說的,IPrincipal.Identity.IsAuthenticated總是返回爲false,所以授權失敗並且404響應返回給客戶端。沒有什麼事情發生,IPrincipal似乎沒有正確實例化。就具體而言,它的行爲幾乎與我上面發佈的[鏈接之一]完全一樣(http://stackoverflow.com/questions/27294032/webapi-owin-identity-is-not-authorized-after-signing-in )。但是,在我的情況下刪除config.SuppressDefaultHostAuthentication()導致IPrincipal變爲空。 – joelmdev

回答

4

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

試試這個順序在Configuration()方法:

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

我希望它能幫助。

+0

太近了!這解決了WebAPI中的問題,但導致了完全相同的問題在MVC中呈現。 – joelmdev

+0

請參閱我的更新 – joelmdev

+0

在添加Autofac之前,相同的'ConfigureAuth()'方法適用於MVC和Web Api? – jumuro