web-dev-qa-db-ja.com

IdentityServer4でパスワードなしでアクセストークンを生成する

ROPCフローを使用してIdentityServer4で保護されたASP.NET Core WebApiを作成しました(この例を使用: https://github.com/robisim74/AngularSPAWebAPI )。

パスワードなしでサーバーからaccess_tokenを手動で生成する方法は?

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

新しくリリースされた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);
}
20
Rem

これを実現する別の方法を次に示します。

最初に、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));

        }
    }

次に、このカスタム許可をIDスタートアップクラスに追加します

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

これを使って:
http://docs.identityserver.io/en/latest/topics/tools.html

IDサーバーに付属のこのツールを使用します。
ディペンデンシーインジェクションで受け取るには、コンストラクターで宣言します
IdentityServer4.IdentityServerTools_identityServerTools

 
 var issuer = "http://" + httpRequest.Host.Value; 
 var token = await _identityServerTools.IssueJwtAsync(
 30000、
 issuer、
 new System.Security.Claims.Claim [1] 
 {
新しいSystem.Security.Claims.Claim( "cpf"、cpf)
} 
); 
 
3
David Madi

元の質問に対する私のコメントに加えて。暗黙的/ハイブリッドフロー内に偽装機能を実装します。ユーザーが「特権管理者」であると判断された場合は、認証後に、なりすましたいアカウントを入力/選択できる追加のステップを提示します。それが完了したら、IDサーバーで選択したユーザーとしてセッションを確立するだけです(また、偽装されたセッションであり、だれが偽装を行っているかを示す追加のクレームを保存することもできます)。トークンは、パスワードを知らなくても、あたかもそのユーザーであるかのように発行されます。

さらに、自分でトークンを作成する場合は、IdSrv4によって提供されるITokenCreationServiceを確認してください。これを独自のコントローラー/サービス/何にでも挿入し、CreateTokenAsync(Token token)を使用して、任意のクレームを持つ署名付きJWTを生成できます。

3
mackie