2015-01-01 11 views
9

Implementazione di ASP.Net Identity 2 in un sistema WebApi. Per gestire mail di conferma per i nuovi account, ho dovuto creare un costume ApplicationUserManager e registrarlo in modo che sarebbe stato creato per ogni richiesta:UserManager personalizzato non disponibile in OAuthAuthorizationServerProvider

public class IdentityConfig{ 
    public static void Initialize(IAppBuilder app) 
    { 
     [snip] 
     app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 
    } 

funzioni correttamente all'interno di un ApiController come questo:

public class AccountController : ApiController 
{ 
    public ApplicationUserManager UserManager 
    { 
     get 
     { 
      return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); 
     } 
    } 

il problema che sto affrontando è che il metodo ApplicationUserManager.Create non viene chiamato prima provo ad accedere nel metodo di creazione OAuth Token:

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider 
{ 
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     var mgr = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); 

Nel codice precedente, mgr è nullo perché GetUserManager recupera nulla

Il metodo di creazione di token è in qualche modo precedente nella pipeline, in modo tale che i metodi CreatePerOwinContext non sono stati ancora chiamati? In tal caso, qual è il modo migliore di memorizzare nella cache un ApplicationUserManager in modo che possa essere utilizzato all'interno di GrantResourceOwnerCredentials?

risposta

14

Questo era difficile. Si scopre che il codice di avvio deve essere fatto in un certo ordine.

Questo codice funzionerà.

public class IdentityConfig{ 
    public static void Initialize(IAppBuilder app) 
    { 
     // correct... first create DB context, then user manager, then register OAuth Provider 
     app.CreatePerOwinContext(AuthContext.Create); 
     app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 
      Provider = new SimpleAuthorizationServerProvider() 
     }; 
     app.UseOAuthAuthorizationServer(OAuthServerOptions); 
     app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 
    } 
} 

Se si modifica l'ordine di come si registra il codice con l'applicazione, è possibile ottenere conseguenze non intenzionali. Questo codice fa sì ApplicationUserManager ad essere nullo all'interno del metodo di token generazione GrantResourceOwnerCredentials

// wrong... these two lines must be after the ApplicationUserManager.Create line 
app.UseOAuthAuthorizationServer(OAuthServerOptions); 
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 

[snip] 

app.CreatePerOwinContext(AuthContext.Create); 
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

mentre io sono a esso, ecco un'altra cosa che potrebbe inciampare qualcuno. Queste linee causano AuthContext ad essere nullo all'interno dei GrantResourceOwnerCredentials metodo di token generazione

// wrong... The AuthContext must be instantiated before the ApplicationUserManager 
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 
app.CreatePerOwinContext(AuthContext.Create); 

[snip] 

app.UseOAuthAuthorizationServer(OAuthServerOptions); 
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 
4

non utilizzare HttpContext.Current.GetOwinContext() in GrantResourceOwnerCredentials come si dispone già di un contesto: (OAuthGrantResourceOwnerCredentialsContext context)

Invece fare questo:

var mgr = context.OwinContext.GetUserManager<ApplicationUserManager>(); 

CreatePerOwinContext viene creato per ogni richiesta così si dovrebbe essere in grado di recuperare l'oggetto ApplicationUserManager . Dovrebbe essere chiamato immediatamente, al Startup. Forse la tua implementazione di avvio non è corretta. Ho scritto una risposta here con alcuni dettagli per l'implementazione.

+0

ho provato troppo context.OwinContext, ma che non ha aiutato. Sei stato sulla strada giusta che aveva qualcosa a che fare con il codice di avvio però. Il codice di avvio deve essere eseguito in un certo ordine non ovvio. Grazie per il suggerimento che mi ha portato alla risposta. – Brian

+0

Devo gettare 'UserManager' da qualche parte nella mia implementazione' OAuthAuthorizationServerProvider'? – Shimmy

+1

@Shimmy: non dovrebbe esserci alcun bisogno. 'UserManager' implementa' IDisposable' e 'CreatePerOwinContext' registra l'oggetto solo per la richiesta. – LeftyX

1

È inoltre possibile ottenere un null restituiti quando chiede l'OwinContext per l'ApplicationUserManager se la linea app.UseWebApi(config); è prima della messa a punto OAuth.

seguito causerà la maggior parte delle chiamate diHttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();

a restituire null.

 HttpConfiguration config = new HttpConfiguration(); 

     WebApiConfig.Register(config); 
     app.UseWebApi(config); <-- Bad location 

     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), 
      Provider = new ApplicationOAuthProvider("clientId"), 
      RefreshTokenProvider = new SimpleRefreshTokenProvider() 
     }; 

     app.UseOAuthAuthorizationServer(OAuthServerOptions); 
     app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 
     app.UseOAuthBearerTokens(OAuthOptions); 

Spostamento app.UseWebApi(config); sotto l'applicazione.I metodi UseOAuth ti permetteranno di ottenere ApplicationUserManager da OwinContext.

questo funziona per me:

 HttpConfiguration config = new HttpConfiguration(); 
     WebApiConfig.Register(config); 

     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), 
      Provider = new ApplicationOAuthProvider("clientId"), 
      RefreshTokenProvider = new SimpleRefreshTokenProvider() 
     }; 

     app.UseOAuthAuthorizationServer(OAuthServerOptions); 
     app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 
     app.UseOAuthBearerTokens(OAuthOptions); 

     app.UseWebApi(config); // <- Moved 
+0

Quindi, vuoi dire fare tutte le operazioni di avvio dell'identità prima di eseguire l'inizializzazione dell'API Web? – Brian

+0

Riformulerò la risposta, era mal formulata. Ho avuto lo stesso problema, ma la tua risposta accettata mi ha portato alla mia soluzione. Per me, tutte le chiamate verso:. 'HttpContext.Current.GetOwinContext() GetUserManager ();' sarebbe tornato null se avevo 'app.UseWebApi (config);' prima del mio app. Utilizza le chiamate OOuth. Spostamento 'app.UseWebApi (config);' dopo la mia configurazione OAuth causa che GetUserManager chiama per poi funzionare. Per rispondere direttamente alla tua domanda, sì, questo ha fatto sì che le cose funzionassero per me. –

+0

Ha senso Chad. Grazie per l'aggiornamento. – Brian

Problemi correlati