J'ai créé ASP.NET Core WebApi protégé avec IdentityServer4 en utilisant le flux ROPC (en utilisant cet exemple: https://github.com/robisim74/AngularSPAWebAPI ).
Comment générer manuellement access_token à partir du serveur sans mot de passe?
[HttpPost("loginas/{id}")]
[Authorize(Roles = "admin")]
public async Task<IActionResult> LoginAs(int id, [FromServices] ITokenService TS,
[FromServices] IUserClaimsPrincipalFactory<ApplicationUser> principalFactory,
[FromServices] IdentityServerOptions options)
{
var Request = new TokenCreationRequest();
var User = await userManager.FindByIdAsync(id.ToString());
var IdentityPricipal = await principalFactory.CreateAsync(User);
var IdServerPrincipal = IdentityServerPrincipal.Create(User.Id.ToString(), User.UserName, IdentityPricipal.Claims.ToArray());
Request.Subject = IdServerPrincipal;
Request.IncludeAllIdentityClaims = true;
Request.ValidatedRequest = new ValidatedRequest();
Request.ValidatedRequest.Subject = Request.Subject;
Request.ValidatedRequest.SetClient(Config.GetClients().First());
Request.Resources = new Resources(Config.GetIdentityResources(), Config.GetApiResources());
Request.ValidatedRequest.Options = options;
Request.ValidatedRequest.ClientClaims = IdServerPrincipal.Claims.ToArray();
var Token = await TS.CreateAccessTokenAsync(Request);
Token.Issuer = "http://" + HttpContext.Request.Host.Value;
var TokenValue = await TS.CreateSecurityTokenAsync(Token);
return Ok(TokenValue);
}
Pour un IdentityServer 2.0.0 nouvellement publié, le code a besoin de quelques modifications:
[HttpPost("loginas/{id}")]
[Authorize(Roles = "admin")]
public async Task<IActionResult> LoginAs(int id, [FromServices] ITokenService TS,
[FromServices] IUserClaimsPrincipalFactory<ApplicationUser> principalFactory,
[FromServices] IdentityServerOptions options)
{
var Request = new TokenCreationRequest();
var User = await userManager.FindByIdAsync(id.ToString());
var IdentityPricipal = await principalFactory.CreateAsync(User);
var IdentityUser = new IdentityServerUser(User.Id.ToString());
IdentityUser.AdditionalClaims = IdentityPricipal.Claims.ToArray();
IdentityUser.DisplayName = User.UserName;
IdentityUser.AuthenticationTime = System.DateTime.UtcNow;
IdentityUser.IdentityProvider = IdentityServerConstants.LocalIdentityProvider;
Request.Subject = IdentityUser.CreatePrincipal();
Request.IncludeAllIdentityClaims = true;
Request.ValidatedRequest = new ValidatedRequest();
Request.ValidatedRequest.Subject = Request.Subject;
Request.ValidatedRequest.SetClient(Config.GetClients().First());
Request.Resources = new Resources(Config.GetIdentityResources(), Config.GetApiResources());
Request.ValidatedRequest.Options = options;
Request.ValidatedRequest.ClientClaims = IdentityUser.AdditionalClaims;
var Token = await TS.CreateAccessTokenAsync(Request);
Token.Issuer = HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value;
var TokenValue = await TS.CreateSecurityTokenAsync(Token);
return Ok(TokenValue);
}
Voici une autre façon d'y parvenir:
créez d'abord une subvention personnalisée nommée loginBy
public class LoginByGrant : ICustomGrantValidator
{
private readonly ApplicationUserManager _userManager;
public string GrantType => "loginBy";
public LoginByGrant(ApplicationUserManager userManager)
{
_userManager = userManager;
}
public async Task<CustomGrantValidationResult> ValidateAsync(ValidatedTokenRequest request)
{
var userId = Guid.Parse(request.Raw.Get("user_id"));
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return await Task.FromResult<CustomGrantValidationResult>(new CustomGrantValidationResult("user not exist"));
var userClaims = await _userManager.GetClaimsAsync(user.Id);
return
await Task.FromResult<CustomGrantValidationResult>(new CustomGrantValidationResult(user.Id.ToString(), "custom", userClaims));
}
}
puis ajoutez cette allocation personnalisée dans la classe de démarrage d'identité
factory.CustomGrantValidators.Add(
new Registration<ICustomGrantValidator>(resolver => new LoginByGrant(ApplicaionUserManager)));
et enfin dans votre api
public async Task<IHttpActionResult> LoginBy(Guid userId)
{
var tokenClient = new TokenClient(Constants.TokenEndPoint, Constants.ClientId, Constants.Secret);
var payload = new { user_id = userId.ToString() };
var result = await tokenClient.RequestCustomGrantAsync("loginBy", "customScope", payload);
if (result.IsError)
return Ok(result.Json);
return Ok(new { access_token = result.AccessToken, expires_in = result.ExpiresIn});
}
Utilisez ceci:
http://docs.identityserver.io/en/latest/topics/tools.html
Utilisez cet outil fourni avec le serveur d'identité:
Déclarez-le dans le constructeur , pour recevoir par injection de dépendance.
IdentityServer4.IdentityServerTools _identityServerTools
var issuer = "http: //" + httpRequest.Host.Value; var token = attendent _identityServerTools.IssueJwtAsync ( 30000, émetteur, nouveau System.Security.Claims.Claim [1] { nouveau System.Security.Claims.Claim ("cpf", cpf) } );
Suite à mon commentaire sur votre question initiale. Implémentez une fonction d'emprunt d'identité dans le flux implicite/hybride. Si un utilisateur est déterminé à être un "super administrateur", présentez-lui une étape supplémentaire après l'authentification qui lui permet d'entrer/sélectionner le compte qu'il souhaite emprunter. Une fois cela fait, établissez simplement la session sur le serveur d'identité en tant qu'utilisateur sélectionné (et éventuellement stockez des revendications supplémentaires indiquant qu'il s'agit d'une session empruntée et qui effectue l'emprunt d'identité). Tous les jetons seront alors émis comme si vous étiez cet utilisateur et tout cela sans avoir à connaître le mot de passe.
De plus, si vous souhaitez créer vous-même des jetons, jetez un œil au service ITokenCreationService fourni par IdSrv4. Vous pouvez l'injecter dans votre propre contrôleur/service/quoi que ce soit et utiliser CreateTokenAsync (jeton de jeton) pour générer un JWT signé avec toutes les revendications que vous aimez.