как мога да получа токен от крайна точка на токен без потребителско име и парола в 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 искам потребителите да се регистрират и влизат с телефонен номер и sms активиране. Когато потребителят изпрати 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
Имам asp.net core web api. Как мога да вляза. Мисля, че трябва да върна токена. Как мога да намеря токена? - 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