E 'difficile rispondere a questa domanda, e dal momento che c'è un sacco che ha bisogno per essere incluso, ho cercato di separare alcuni problemi.
reclami
Ci sono due modi per aggiungere crediti al ClaimsIdentity.
- Rivendicazioni persistenti nel negozio (nel database le tabelle AspNetUserClaims, AspNetRoleClaims). Per aggiungere reclami utilizzare UserManager.AddClaim o RoleManager.AddClaim. I ruoli (AspNetUserRoles) sono speciali, poiché sono anche conteggiati come attestazioni.
- Aggiungi reclami nel codice. È possibile aggiungere attestazioni dalla classe ApplicationUser (utile per le proprietà estese di IdentityUser) o nel flusso.
Si prega di notare la differenza! Mentre in tutti i casi si chiama AddClaim, la prima variante aggiunge le rivendicazioni allo store, mentre la seconda variante aggiunge le attestazioni direttamente a ClaimsIdentity.
Quindi, come vengono aggiunte le attestazioni persistenti a ClaimsIdentity? Questo è fatto automaticamente!
Come nota a margine, è possibile estendere IdentityUser con le proprietà, ma è anche possibile aggiungere rivendicazioni utente allo store. In entrambi i casi il reclamo verrà aggiunto a ClaimsIdentity. La proprietà estesa deve essere aggiunta in ApplicationUser.GenerateUserIdentityAsync:
public class ApplicationUser : IdentityUser
{
public string DisplayName { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("DisplayName", DisplayName));
return userIdentity;
}
}
flusso
Prima di rilasciare un nuovo access_token il server deve convalidare l'utente. Potrebbero esserci motivi per cui il server non può emettere un nuovo access_token. Anche la configurazione modificata deve essere presa in considerazione. Esistono due provider per questa configurazione. Il provider access_token e il provider refresh_token.
Quando un client effettua una richiesta all'endpoint token (grant_type = *), AccessTokenProvider.ValidateClientAuthentication viene eseguito per primo. Se stai usando client_credentials, puoi fare qualcosa qui. Ma per il flusso corrente assumiamo context.Validated();
Il provider supporta vari flussi. È possibile leggere a questo proposito qui: https://msdn.microsoft.com/en-us/library/microsoft.owin.security.oauth.oauthauthorizationserverprovider(v=vs.113).aspx
Il provider è stato creato come opt-in. Se non si esegue l'override dei metodi determinati, l'accesso viene negato.
token di accesso
Per ottenere un token di accesso, le credenziali devono essere inviati. Per questo esempio assumerò 'grant_type = password'. In AccessTokenProvider.GrantResourceOwnerCredentials vengono verificate le credenziali, ClaimsIdentity è configurato e viene emesso un token.
Per aggiungere un refresh_token al ticket, è necessario eseguire l'override di AccessTokenProvider.GrantRefreshToken. Qui hai due opzioni: respingere il token. Poiché il refresh_token è stato revocato o per un altro motivo per cui l'utente non può più utilizzare il token di aggiornamento. Oppure imposta un nuovo ClaimsIdentity per generare un nuovo access_token per il ticket.
class AccessTokenProvider : OAuthAuthorizationServerProvider
{
public override async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
// Reject token: context.Rejected(); Or:
// chance to change authentication ticket for refresh token requests
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var appUser = await userManager.FindByNameAsync(context.Ticket.Identity.Name);
var oAuthIdentity = await appUser.GenerateUserIdentityAsync(userManager);
var newTicket = new AuthenticationTicket(oAuthIdentity, context.Ticket.Properties);
context.Validated(newTicket);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var appUser = await userManager.FindAsync(context.UserName, context.Password);
if (appUser == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var propertyDictionary = new Dictionary<string, string> { { "userName", appUser.UserName } };
var properties = new AuthenticationProperties(propertyDictionary);
var oAuthIdentity = await appUser.GenerateUserIdentityAsync(userManager);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
// Token is validated.
context.Validated(ticket);
}
}
Se il contesto ha un ticket convalidato, viene chiamato il RefreshTokenProvider. Nel metodo Create è possibile impostare il tempo di scadenza e scegliere di aggiungere il token di aggiornamento al ticket. Non emettere nuovi token mentre quello attuale non è ancora scaduto. In caso contrario, l'utente potrebbe non dover mai più effettuare il login!
È sempre possibile aggiungere il refresh_token se è in qualche modo persistente. Oppure puoi aggiungere un nuovo refresh_token solo al login. L'utente è identificato in modo che il 'vecchio' refresh_token non abbia più importanza dal momento che scadrà prima che il nuovo refresh_token faccia. Se si desidera utilizzare solo un refesh_token attivo, è necessario mantenerlo.
class RefreshTokenProvider : AuthenticationTokenProvider
{
public override void Create(AuthenticationTokenCreateContext context)
{
var form = context.Request.ReadFormAsync().Result;
var grantType = form.GetValues("grant_type");
// do not issue a new refresh_token if a refresh_token was used.
if (grantType[0] != "refresh_token")
{
// 35 days.
int expire = 35 * 24 * 60 * 60;
context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddSeconds(expire));
// Add the refresh_token to the ticket.
context.SetToken(context.SerializeTicket());
}
base.Create(context);
}
public override void Receive(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
base.Receive(context);
}
}
Questa è solo una semplice implementazione del flusso refresh_token e non completa né testata. È solo per darvi alcune idee sull'implementazione del flusso refresh_token. Come puoi vedere, non è difficile aggiungere attestazioni a ClaimsIdentity. Non ho aggiunto codice in cui vengono mantenute le dichiarazioni persistenti. Tutto quello che importa è che le richieste persistenti sono automaticamente aggiunto!
Si prega di notare che ho ripristinato il ClaimsIdentity (nuovo ticket) su aggiornamento del token di accesso utilizzando il refresh_token. Ciò creerà un nuovo ClaimsIdentity con lo stato corrente delle attestazioni.
Terminerò con un'ultima osservazione. Stavo parlando dei ruoli che vengono rivendicati. È probabile che User.IsInRole controlli la tabella AspNetUserRoles. Ma non è così. Poiché i ruoli sono rivendicazioni, controlla la raccolta sinistri per i ruoli disponibili.
Hai mai trovato una soluzione e sei ancora interessato se non? –
@RuardvanElburg Apprezzerei comunque una buona risposta :) –