web-dev-qa-db-fra.com

Générer un jeton d'accès avec IdentityServer4 sans mot de passe

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?

17
Rem
[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);
}
20
Rem

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});
       }
3
xray

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) 
} 
); 
 
3
David Madi

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.

3
mackie