2015-01-29 44 views
6

Kurucuya bir hizmet arabirimi enjekte ettiğim bir denetleyicim var. Hizmet, arabirimine de yapıcı arayüzleri enjekte etti. IoC konteynerinin (Unity), belirli bir arabirim için döndürdüğü sınıflardan birini oluştururken kullanıcı hakkındaki bilgileri kullanması gerekir. neler oluyorASP.NET MVC Denetleyiciden önce kimlik doğrulaması başlatıldı

, [Yetkilendirme] özelliğinin değerlendirilir önce kontrolör örneğinin oluşturulmasını ve kullanıcı kimlik doğrulaması olmasıdır. Bu, Unity'yi bağımlılık enjeksiyonunu gerçekleştirmeye zorlar ve oturum açmadan önce kullanıcı hakkındaki bilgileri kullanır. Entegre Windows kimlik doğrulaması kullandığımızda bunun hiçbir problemi olmadı, ancak şimdi Azure AD'ye OpenID Connect'i kullanıyoruz ve kullanıcı bilgisi isn ' giriş yapana kadar (kontrol cihazı kapatıldıktan sonra). Orada işlemde önceki kimlik taşımak için benim Owin başlangıç ​​sınıfını yapılandırmak için bir yoldur, ama ben bunun nasıl herhangi örnekler bulamadığını (diğer mesajlar) duydum

. Denetleyicinin başlatılmasından önce gerçekleşmesi gereken kimlik doğrulamasına ihtiyacım var.

[Authorize] 
public class MyController : Controller 
{ 
    private readonly IMyService myService; 

    public MyController(IMyService myService) 
    { 
     this.myService = myService; 
    } 

    // ... 
} 

Birlik Yapılandırma:

public class UnityBootstrap : IUnityBootstrap 
{ 
    public IUnityContainer Configure(IUnityContainer container) 
    { 
     // ... 

     return container 
      .RegisterType<ISomeClass, SomeClass>() 
      .RegisterType<IMyService>(new InjectionFactory(c => 
      { 
       // gather info about the user here 
       // e.g. 
       var currentUser = c.Resolve<IPrincipal>(); 
       var staff = c.Resolve<IStaffRepository>().GetBySamAccountName(currentUser.Identity.Name); 
       return new MyService(staff); 
      })); 
    } 
} 

Owin Başlangıç ​​(Startup.Auth.cs):

İşte

...

Kontrolör sahip olduğumun basitleştirilmiş bir örnek

public void ConfigureAuth(IAppBuilder app) 
{ 
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); 

    app.UseCookieAuthentication(new CookieAuthenticationOptions()); 

    app.UseOpenIdConnectAuthentication(
     new OpenIdConnectAuthenticationOptions 
     { 
      ClientId = this.clientID, 
      Authority = this.authority, 
      PostLogoutRedirectUri = this.postLogoutRedirectUri, 
      Notifications = new OpenIdConnectAuthenticationNotifications 
      { 
       RedirectToIdentityProvider = context => 
       { 
        context.ProtocolMessage.DomainHint = this.domainHint; 
        return Task.FromResult(0); 
       }, 
       AuthorizationCodeReceived = context => 
       { 
        var code = context.Code; 

        var credential = new ClientCredential(this.clientID, this.appKey.Key); 
        var userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; 
        var authContext = new AuthenticationContext(this.authority, new NaiveSessionCache(userObjectID)); 
        var result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, this.graphUrl); 
        AzureAdGraphAuthenticationHelper.Token = result.AccessToken; 
        return Task.FromResult(0); 
       } 
      } 
     }); 
} 
+0

Ben de bu takıldı. Temel denetleyicinin yapıcısında bir kullanıcı gerekiyordu ve 'AuthorizedAttribute' adlı kullanıcının kullanıcıyı harekete geçirmesinden önce çağrılan kurucuyu görmeye şaşırmıştı. –

+1

Neden böyle bir açıklaması http://stackoverflow.com/a/4462767/10245 –

cevap

4

Af özel olarak sorunumu online olarak ele alan hiçbir şey bulamadığı için, ASP.NET MVC 5 application lifecycle'u incelemeye karar verdim. CreateController yöntemini tanımlayabileceğim özel bir IControllerFactory (veya DefaultControllerFactory öğesinden devralma) oluşturabileceğimi buldum.

CreateController sırasında, ben kullanıcı kimlik doğrulaması olup olmadığını görmek için kontrol edin. Eğer öyleyse, DefaultControllerFactory'nin normalde olduğu gibi denetleyiciyi oluşturmasına izin vermeliyim.

Kullanıcı kimlik doğrulaması yapılmadıysa, RequestContext solunda değiştirilen denetleyici yerine (çok sayıda bağımlı katmanı olan) yerine (çok) basit "Auth" denetleyicimi oluşturuyorum.

Auth denetleyicisi, bağımlılığı olmadığı için sorunsuz olarak başlatılacaktır. Not: Auth denetleyicisinde hiçbir eylem yürütülmez. Yetkilendirme denetleyicisi oluşturulduktan sonra, global AuthorizeAttribute başlatılır ve kullanıcı kimlik doğrulamaya (OpenID Connect Azure AD ve ADFS aracılığıyla) yönlendirilir.

oturum açtıktan sonra, inceliğini hala orijinal RequestContext ile Uygulamama geri yönlendirilir. CusomControllerFactory, kullanıcıyı doğrulanmış olarak algılar ve istenen denetleyici oluşturulur.

Bu yöntem benim denetleyicilerimin büyük bir bağımlılık zincirinin enjekte edilmesine sahip olduğundan (örneğin Denetleyici ISomeRepository, ISomeHelper, ISomethingEles ... 'e bağlı ISomeService'ye bağlıdır) ve kullanıcı bağımlı oluncaya kadar bağımlılıkların hiçbiri çözülmediğinden içinde.

açmış hala benim orijinal söz konusu soruyordu ulaşmak için nasıl diğer (daha şık) fikirler işitme kesinlikle açığım.


CustomControllerFactory.DI şeyler hiçbirini yapmadan olsa cs

public class CustomControllerFactory : DefaultControllerFactory 
{ 
    public override IController CreateController(RequestContext requestContext, string controllerName) 
    { 
     var user = HttpContext.Current.User; 
     if (user.Identity.IsAuthenticated) 
     { 
      return base.CreateController(requestContext, controllerName); 
     } 

     var routeValues = requestContext.RouteData.Values; 
     routeValues["action"] = "PreAuth"; 
     return base.CreateController(requestContext, "Auth"); 
    } 
} 

Global.asax.cs

public class MvcApplication : HttpApplication 
{ 
    protected void Application_Start() 
    { 
     // ... 
     ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory)); 
    } 

    // ... 
} 

AuthController.cs

public class AuthController : Controller 
{ 
    public ActionResult PreAuth() 
    { 
     return null; 
    } 
}