Создать токен доступа с IdentityServer4 без пароля
Я создал ASP.NET Core WebApi, защищенный IdentityServer4, используя поток ROPC (используя этот пример: https://github.com/robisim74/AngularSPAWebAPI).
Как вручную сгенерировать access_token с сервера без пароля?
5 ответов
[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);
}
Использовать этот:
http://docs.identityserver.io/en/latest/topics/tools.html
Используйте этот инструмент, который поставляется с сервером идентификации:
Объявите это в конструкторе, чтобы получить путем внедрения зависимости.
IdentityServer4.IdentityServerTools _identityServerTools
var isser = "http://" + httpRequest.Host.Value; var token = await _identityServerTools.IssueJwtAsync( 30000, эмитента, новый System.Security.Claims.Claim[1] { новый System.Security.Claims.Claim("cpf", cpf) });
Вот еще один способ добиться этого:
сначала создайте настраиваемый грант с именем 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});
}
Немного поздно отвечать.
в моем случае
Generating Access Token Without Password
был еще один
identity server
как организация sso, и наша реализация уже используется, поэтому нам нужно получить токен пользователя со второго (после входа пользователя в систему и перенаправления в наше приложение), извлечь
sub
, проверьте, существует ли он уже (если не вставьте в наш локальный
IdentityServer
), наконец, выберите пользователя и используйте новый грант, чтобы получить токен для пользователя. у вашего клиента должно быть это
granttype
как разрешенные типы грантов (здесь
userexchange
):
см. документацию по серверу идентификации или документацию duende для получения дополнительной информации.
public class TokenExchangeGrantValidator : IExtensionGrantValidator {
protected readonly UserManager<ToranjApplicationUser> _userManager;
private readonly IEventService _events;
public TokenExchangeGrantValidator(ITokenValidator validator, IHttpContextAccessor httpContextAccessor, UserManager<ToranjApplicationUser> userManager
, IEventService events) {
_userManager = userManager;
_events = events;
}
public async Task ValidateAsync(ExtensionGrantValidationContext context) {
var userName = context.Request.Raw.Get("uname");
if (string.IsNullOrEmpty(userName)) {
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var user = await _userManager.FindByNameAsync(userName);
// or use this one, if you are sending userId
//var user = await _userManager.FindByIdAsync(userId);
if (null == user) {
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName, false, context.Request.ClientId));
var customResponse = new Dictionary<string, object>
{
{OidcConstants.TokenResponse.IssuedTokenType, OidcConstants.TokenTypeIdentifiers.AccessToken}
};
context.Result = new GrantValidationResult(
subject: user.Id.ToString(),
authenticationMethod: GrantType,
customResponse: customResponse);
}
public string GrantType => "userexchange";
}
в вашей
startup
с
ConfigureServices
после
var builder = services.AddIdentityServer(...)
добавьте свой недавно созданный класс.
builder.AddExtensionGrantValidator<TokenExchangeGrantValidator>();
вызвать его для получения токена так же просто, как:
POST /connect/token
grant_type=userexchange&
scope=yourapi&
uname=yourusername&
client_id=yourClientId
client_secret=secret
В дополнение к моему комментарию на ваш оригинальный вопрос. Реализовать функцию олицетворения в неявном / гибридном потоке. Если пользователь определен как "супер-администратор", то предоставьте ему дополнительный шаг после аутентификации, который позволит им войти / выбрать учетную запись, которую он хочет выдать. Как только это будет сделано, просто установите сеанс на сервере идентификации в качестве выбранного пользователя (и, возможно, сохраните дополнительные утверждения, обозначающие, что это олицетворенный сеанс и кто выполняет олицетворение). Любые токены будут выданы, как если бы вы были этим пользователем, и все без необходимости знать пароль.
Кроме того, если вы хотите создать токены самостоятельно, взгляните на ITokenCreationService, предоставляемый IdSrv4. Вы можете вставить это в свой собственный контроллер / службу / что угодно и использовать CreateTokenAsync(токен токена) для генерации подписанного JWT с любыми заявками, которые вам нравятся.