Создать токен доступа с IdentityServer4 без пароля

Я создал ASP.NET Core WebApi, защищенный IdentityServer4, используя поток ROPC (используя этот пример: https://github.com/robisim74/AngularSPAWebAPI).

Как вручную сгенерировать access_token с сервера без пароля?

Ответ 1

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

Для недавно выпущенного IdentityServer 2.0.0 код нуждается в некоторых модификациях:

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

Ответ 2

В дополнение к моему комментарию к вашему оригинальному вопросу. Внедрить функцию олицетворения в неявном/гибридном потоке. Если пользователь определен как "супер-администратор", то после их представления им предоставляется дополнительный шаг после проверки подлинности, который позволяет им вводить/выбирать учетную запись, которую они хотят выдавать. Как только это будет сделано, просто установите сеанс на сервере идентификации как выбранный пользователь (и, возможно, сохраните дополнительные требования, обозначающие, что он является олицетворением сеанса и кто выполняет олицетворение). Любые жетоны будут выдаваться так, как если бы вы были этим пользователем и все без необходимости знать пароль.

Кроме того, если вы хотите сами создавать маркеры, посмотрите на ITokenCreationService, предоставленный IdSrv4. Вы можете ввести это в свой собственный контроллер/службу/что угодно и использовать CreateTokenAsync (токен токена) для создания подписанного JWT с любыми претензиями, которые вам нравятся.

Ответ 3

Вот еще один способ добиться этого:

сначала создайте пользовательский грант с именем 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));

        }
    }

затем добавьте это пользовательское разрешение в класс запуска идентификации

    factory.CustomGrantValidators.Add(
                        new Registration<ICustomGrantValidator>(resolver => new LoginByGrant(ApplicaionUserManager)));

и, наконец, в вашем 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});
       }

Ответ 4

Используйте это:
http://docs.identityserver.io/en/latest/topics/tools.html

Используйте этот инструмент, поставляемый с сервером идентификации:
Объявите это в конструкторе, чтобы получить путем внедрения зависимости.
IdentityServer4.IdentityServerTools _identityServerTools

    var issuer = "http://" + httpRequest.Host.Value;  
    var token = await _identityServerTools.IssueJwtAsync(  
        30000,  
        issuer,  
        new System.Security.Claims.Claim[1]   
        {  
            new System.Security.Claims.Claim("cpf", cpf)  
        }  
    );