как я могу получить токен из конечной точки токена без имени пользователя и пароля в identityserver4?

Я использую IdentityServer4 для аутентификации и авторизации пользователей в моем основном веб-API asp.net. Я использую этот API в приложении для Android. Мои пользователи без проблем регистрируются и входят в систему с именем пользователя и паролем. И вот мой токен доступа, который я получил от конечная точка подключения / токена

{
  "alg": "RS512",
  "typ": "at+jwt"
}
{
  "nbf": 1600324303,
  "exp": 1631860303,
  "iss": "https://myIdentityServerApi.com",
  "aud": [
    "IdentityServerApi",
    "MyAPI1"
  ],
  "client_id": "MyApp1",
  "sub": "521d198c-3657-488e-997e-3e50d756b353",
  "auth_time": 1600324302,
  "idp": "local",
  "role": "Admin",
  "name": "myusername",
  "scope": [
    "openid",
    "IdentityServerApi",
    "MyAPI1"
  ],
  "amr": [
    "pwd"
  ]
}

Теперь в моем новом приложении для Android я хочу, чтобы пользователи регистрировались и входили в систему с номером телефона и активацией по смс. Когда Пользователь отправляет ActivationCode, я должен отправить ему токен доступа. Но как я могу получить токен из конечной точки токена без имени пользователя и пароля?

Ниже я хотел сгенерировать токен вручную, но сгенерированный токен не работает.

        [HttpPost("Activate")]
        [AllowAnonymous]
        public async Task<IActionResult> Activate([FromBody] SignUpPhoneModel model)
        {
            if (string.IsNullOrWhiteSpace(model.PhoneNumber))
            {
                return BadRequest("Phone Number is Empty");
            }

            PhoneValidation pv = new PhoneValidation();


            IdentityUser CurrentUser = await db.Users.Where(e => e.PhoneNumber == model.PhoneNumber).FirstAsync();
            if (!await UserManager.VerifyChangePhoneNumberTokenAsync(CurrentUser, model.ActivationCode, model.PhoneNumber))
            {
                return BadRequest("Activation Code is not correct");
            }
            else
            {
                //Here user is activated and should get token But How?
                CurrentUser.PhoneNumberConfirmed = true;
                List<string> UserRoles = (await UserManager.GetRolesAsync(CurrentUser)).ToList();
                var tokenHandler = new JwtSecurityTokenHandler();

                RSACryptoServiceProvider rsap = new RSACryptoServiceProvider(KeyContainerNameForSigning);
                SecurityKey sk = new RsaSecurityKey(rsap.Engine);
                List<Claim> UserClaims = new List<Claim>() {
                    new Claim(JwtRegisteredClaimNames.Sub, CurrentUser.Id),

                };
                foreach (var r in UserRoles)
                {
                    UserClaims.Add(new Claim(JwtClaimTypes.Role, r));
                }
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                     Issuer= "https://myidentityserverapi.com",
                    Audience = "IdentityServerApi,MyAPI",
                     
                    Subject = new ClaimsIdentity(UserClaims),
                    Expires = DateTime.UtcNow.AddDays(365),
                    SigningCredentials = new SigningCredentials(sk, SecurityAlgorithms.RsaSha512),
                };
                var token = tokenHandler.CreateToken(tokenDescriptor);
                TokenModel tm = new TokenModel()
                {
                    access_token = tokenHandler.WriteToken(token)
                };
                return Ok(tm);
            }
        }

Когда я получаю токен сверху (метод действия) в моем приложении, как показано ниже, но он не работает, например, User.Identity.IsAuthenticated ложно. Кто-нибудь знает, как я могу сгенерировать токен, например конечную точку подключения / токена, без имени пользователя и пароля?

  "alg": "RS256",
  "typ": "JWT"
}

{
  "unique_name": "13f2e130-e2e6-48c7-b3ac-40f8dde8087b",
  "role": "Member",
  "nbf": 1600323833,
  "exp": 1718259833,
  "iat": 1600323833
}

Я выбрал правильный метод? Или я должен использовать другой способ, например, другие типы потоков или грантов?




Ответы (3)


Я предполагаю, что ваши пользователи активируют свои ActivationCode через сервер IS4. В этом случае вам не нужно вручную управлять / создавать файл access_token.

Вам просто нужно выполнить ту же процедуру, что и метод Login внутри AccountController, заключающийся в следующем:

  1. Проверьте пользователя с логином / паролем, в вашем случае подтвердите свой ActivationCode

  2. После идентификации пользователя SignIn ваш пользователь с помощью SignInManager. (SignInManager .SignInAsync)

  3. Вызвать событие UserLoginSuccessEvent.

    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId: context?.Client.ClientId));

  4. Наконец, перенаправьте пользователя в ваше веб-приложение.

    return Redirect(model.ReturnUrl);

При перенаправлении в ваше приложение IdentityServer4 отправит пользователю свой access_token.

person Nicolas Law-Dune    schedule 17.09.2020
comment
Я хочу использовать ваш ответ в своем веб-API. Что мне делать с перенаправлением? - person mohsen; 18.09.2020
comment
У меня есть приложение для Android, поэтому я должен вернуть токен пользователю после активации. Мои пользователи получают токен с помощью sms и отправляют его вышеуказанному методу. Затем пользователь активируется, тогда они должны получить токен. Но как я могу сгенерировать токен? Должен ли я получить токен из подключения / токена? но как, когда у меня нет имени пользователя и пароля - person mohsen; 19.09.2020
comment
Нет необходимости генерировать токен, это ваше действие при перенаправлении на ваш redirectUrl отправит в ваше приложение токен. Для приложения Android просто используйте глубокую ссылку для перенаправления в свое приложение, а затем получите токен из параметра. - person Nicolas Law-Dune; 19.09.2020
comment
Я не знаю, как использовать это в моем базовом веб-API asp.net, у которого есть identityserver4. У вас есть какой-нибудь наставник - person mohsen; 26.09.2020

Я думаю, все, что вам нужно сделать, это то, что когда пользователь подтверждает код активации, вы делаете то же самое, что описано в:

public async Task<IActionResult> Login(LoginInputModel model, string button) { }

Как указано в справочном классе AccountController.cs.

person Tore Nestenius    schedule 17.09.2020
comment
Вышеупомянутый метод или метод активации - это метод входа в систему. Но сгенерированный токен не работает. Я хочу знать, как соединение / токен генерирует токен, а затем сгенерировать токен - person mohsen; 17.09.2020
comment
думаю, что сложно генерировать свои собственные токены, лучше подписать пользователя, подделав логин, используя логику в методе входа выше ... Лучше всегда следовать официальным потокам и подходам, чем пытаться взломать собственное решение. Аутентификация с использованием логина / пароля никогда не является требованием, вы можете настроить код в учетной записи или ExternalController, именно так я бы это сделал. - person Tore Nestenius; 18.09.2020
comment
У меня есть основной веб-api asp.net.Как я могу войти. Думаю, мне нужно вернуть токен.Как мне найти токен? - person mohsen; 19.09.2020
comment
что вы хотите войти? Вы хотите войти в систему пользователя или приложения для доступа к вашему API? В зависимости от этого вы используете либо поток кода авторизации, либо поток учетных данных клиента. Независимо от того, что, вы используете обработчик аутентификации AddOpenIdConnect, чтобы получить токен от IdentityServe. - person Tore Nestenius; 20.09.2020
comment
Я хочу войти в систему пользователя, поэтому я думаю, что мне следует использовать поток кода авторизации. Но я не вижу хорошего примера и учебника о том, как я могу реализовать это. Знаете ли вы учебник или пример? - person mohsen; 20.09.2020

Наконец, я создаю токен доступа вот так:

[HttpPost("Activate")]
        [AllowAnonymous]
        public async Task<IActionResult> Activate([FromBody] SignUpPhoneModel model, [FromServices] ITokenService TS, [FromServices] IUserClaimsPrincipalFactory<JooyaIdentityUser> principalFactory, [FromServices] IdentityServerOptions options)
        {           
            JooyaIdentityUser CurrentUser = await db.Users.Where(e => e.PhoneNumber == model.PhoneNumber).FirstOrDefaultAsync();
            
            if (!await UserManager.VerifyChangePhoneNumberTokenAsync(CurrentUser, model.ActivationCode, model.PhoneNumber))
            {
                return BadRequest("Activation Code in not correct");
            }
            CurrentUser.PhoneNumberConfirmed = true;
            await db.SaveChangesAsync();
            await UserManager.UpdateSecurityStampAsync(CurrentUser);
            var Request = new TokenCreationRequest();
            var IdentityPricipal = await principalFactory.CreateAsync(CurrentUser);
            var IdentityUser = new IdentityServerUser(CurrentUser.Id.ToString());
            IdentityUser.AdditionalClaims = IdentityPricipal.Claims.ToArray();
            IdentityUser.DisplayName = CurrentUser.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(SeedConfig.GetClients().Where(e => e.ClientId == model.ClientId).First());
            List<ApiResource> Apis = new List<ApiResource>();
            Apis.Add(SeedConfig.GetApis().Where(e => e.Name == "IdentityServerApi").First());
            Apis.Add(SeedConfig.GetApis().Where(e => e.Name == model.ApiName).First());
            Request.Resources = new Resources(SeedConfig.GetIdentityResources(), Apis);
            Request.ValidatedRequest.Options = options;
            Request.ValidatedRequest.ClientClaims = IdentityUser.AdditionalClaims;
            var Token = await TS.CreateAccessTokenAsync(Request);
            Token.Issuer = HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value;
            Token.Lifetime = 32000000;
            var TokenValue = await TS.CreateSecurityTokenAsync(Token);
            TokenModel tm = new TokenModel()
            {
                access_token = TokenValue
            };
            return Ok(tm);
        }
person mohsen    schedule 05.10.2020