Situazione: Ho un progetto Web API 2 che funge da server di autorizzazione (/ token endpoint) e un server di risorse. Sto usando il modello che esce dalla scatola con ASP.Net Web API meno qualsiasi riferimento MVC. Lo Start.Auth è configurato come di seguito:Come memorizzare i token bearer quando MVC e Web API si trovano in diversi progetti
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
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("/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = ConfigurationManager.AppSettings["Test_Facebook_AppId"],
AppSecret = ConfigurationManager.AppSettings["Test_Facebook_AppSecret"],
//SendAppSecretProof = true,
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(0);
}
}
};
facebookAuthenticationOptions.Scope.Add("email user_about_me user_location");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
}
Il MVC 5 client (progetto diverso) utilizza l'applicazione Web API per l'autorizzazione e dati. Di seguito è riportato il codice per recuperare il token portatore in caso di negozio Nome utente/password:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
model.ExternalProviders = await GetExternalLogins(returnUrl);
return View(model);
}
var client = Client.GetClient();
var response = await client.PostAsync("Token",
new StringContent(string.Format("grant_type=password&username={0}&password={1}", model.Email, model.Password), Encoding.UTF8));
if (response.IsSuccessStatusCode)
{
return RedirectToLocal(returnUrl);
}
return View();
}
Problema
ho potuto recuperare il portatore token e quindi aggiungerlo alla intestazione di autorizzazione per le chiamate successive. Penso che sarebbe ok in caso di un'Angular App o di una SPA. Ma penso che ci dovrebbe essere qualcosa in MVC che lo gestisce per me, come lo memorizza automaticamente in un cookie e invia il cookie alle richieste successive. Ho cercato in giro parecchio e ci sono post che suggeriscono questo (Registering Web API 2 external logins from multiple API clients with OWIN Identity) ma non sono stato in grado di capire cosa fare dopo aver ottenuto un token.
Devo aggiungere qualcosa nell'app MVC Startup.Auth?
Idealmente, ho bisogno della funzionalità che l'AccountController nel modello ASP.Net (MVC + Web API) fornisce di casella (accessi, registro, accessi esterni, password dimenticata ecc. Ecc.) Ma con MVC e Web API in diversi progetti.
C'è un modello o un repository git che ha questo codice piastra?
Grazie in anticipo!
Aggiornamento Incorporando suggerimenti @FrancisDucharme, sotto è il codice per GrantResourceOwnerCredentials().
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
//Add a response cookie...
context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
Ma non riesco ancora a ottenere quel Cookie o a capire cosa fare dopo.
Domande ribadendo:
- Quale sarebbe il modo corretto per autenticare, autorizzare e chiamare i metodi Web API (Auth e server di risorse) da un client MVC?
- C'è codice o modello di codice per AccountController che esegue l'impianto idraulico di base (Login, registro - interno/esterno, password dimenticata, ecc.)?
Se la propria API Web restituisce l'hash del token nei cookie di risposta, il client restituirà questo cookie per tutte le richieste successive, presupponendo che il browser client abbia i cookie abilitati. –
@FrancisDucharme potresti elaborare questo processo per favore. Sto usando l'endpoint token standard e la configurazione che esce dal modello di API web. –
Il tuo problema principale è che vuoi che il client MVC aggiunga sempre automaticamente l'intestazione 'Authorization: Bearer', giusto? –