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

#asp.net-core #authentication #asp.net-core-webapi #identityserver4 #access-token

#asp.net-ядро #аутентификация #asp.net-core-webapi #идентификационный сервер4 #токен доступа #identityserver4

Вопрос:

Я использую IdentityServer4 для аутентификации и авторизации пользователей в моем asp.net основной веб-api.Я использую этот 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 я хочу, чтобы пользователи регистрировались и входили в систему с номером телефона и активацией sms.
Когда пользователь отправляет код активации, я должен отправить ему токен доступа.Но как я могу получить токен от конечной точки токена без имени пользователя и пароля?

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

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

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

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

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

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

Ответ №1:

Я полагаю, что ваши пользователи активируют их 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 .

Комментарии:

1. Я хочу использовать ваш ответ в своем веб-api. что мне делать с перенаправлением?

2. У меня есть приложение для Android, поэтому я должен вернуть токен пользователю после активации. Мои пользователи получают токен с помощью sms и отправляют его вышеуказанным методом. затем пользователь активируется, затем он должен получить токен. Но как я могу сгенерировать токен? Должен ли я получить токен из connect / token? но как, если у меня нет имени пользователя и пароля

3. Нет необходимости генерировать токен, это ваше действие при перенаправлении на ваш redirectUrl отправит вашему приложению токен. Для приложения Android просто используйте глубокую ссылку для перенаправления на ваше приложение, а затем извлеките токен из параметра.

4. Я не знаю, как использовать это в моем asp.net основной веб-api, который имеет identityserver4.do у вас есть какой-нибудь репетитор

Ответ №2:

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

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

Как найдено в ссылочном классе AccountController.cs.

Комментарии:

1. Вышеупомянутый метод или метод активации — это метод входа в систему. но сгенерированный токен не работает.я хочу знать, как connect / token генерирует токен, а затем генерирует токен

2. подумайте, что сложно генерировать свои собственные токены, лучше подписать пользователя, «подделав» логин, используя логику в методе входа в систему выше… Лучше всегда следовать официальным потокам и подходам, чем пытаться взломать собственное решение. Аутентификация с помощью логина / пароля никогда не является обязательным требованием, вы можете настроить код в учетной записи или ExternalController, именно так я бы это сделал.

3. У меня есть asp.net основной веб-api. Как я могу войти. Я думаю, что я должен вернуть токен. Как я могу найти токен?

4. что вы хотите для входа? Вы хотите войти в систему пользователя или приложения для доступа к вашему API? Исходя из этого, вы либо используете поток кода авторизации, либо поток учетных данных клиента. Независимо от того, что вы используете обработчик аутентификации AddOpenIdConnect для получения токена из IdentityServe

5. Я хочу войти в систему пользователя, поэтому я думаю, что мне следует использовать поток кода авторизации. но я не вижу хорошего примера и руководства о том, как я могу это реализовать. вы знаете учебник или пример?

Ответ №3:

Я, наконец, создаю токен доступа следующим образом:

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