使用IdentityServer4生成访问令牌,无需密码

Rem*_*Rem 15 asp.net-core identityserver4

我使用ROPC流创建了使用IdentityServer4保护的ASP.NET Core WebApi(使用此示例:https://github.com/robisim74/AngularSPAWebAPI).

如何在没有密码的情况下从服务器手动生成access_token?

Rem*_*Rem 19

[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);
}
Run Code Online (Sandbox Code Playgroud)

对于新发布的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);
}
Run Code Online (Sandbox Code Playgroud)

  • 对于使用 duende 身份服务器 6 的用户,资源属性已被弃用,请使用下面的行而不是 `request.ValidatedResources = new ResourceValidationResult(new Resources(identityResource, apiResource, apiScope));` (2认同)

Dav*_*adi 15

使用这个:http :
//docs.identityserver.io/en/latest/topics/tools.html

使用身份服务器自带的这个工具:
在构造函数中声明它,通过依赖注入来接收。
IdentityServer4.IdentityServerTools _identityServerTools

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

  • 好主意!但它有一点限制:它无法生成 RefreshToken,并且需要从用户及其角色手动生成声明 (2认同)

xra*_*ray 5

这是实现此目的的另一种方法:

首先创建一个名为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));

        }
    }
Run Code Online (Sandbox Code Playgroud)

然后在身份启动类中添加此自定义授权

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

Run Code Online (Sandbox Code Playgroud)

最后在你的 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});
       }
Run Code Online (Sandbox Code Playgroud)