Аутентификация asp .net core через IdentityServer4

    Тут не будет ничего необычного, один фреймворк «IdentityServer4» будет выполнять аутентификацию по логину и паролю на неком Api, плюс еще обрабатывать refresh_token.

    Работать он будет с существующим IdentityDbContext, IdentityUser.

    По итогу получится сценарий при котором, для каждой аутентификации будет выдан и сохранен в таблицу «PersistedGrants» один refresh_token. Это один из четырех типов разрешений OAuth 2.0:

    Учётные данные владельца ресурса (Resource Owner Password Credentials): используются доверенными приложениями, например приложениями, которые являются частью самого сервиса.

    Все работы по обслуживанию токенов берет на себя фреймворк.

    Итак начнем.

    Для указания метода разрешения задаются «клиенты», у меня будет один:

    DataLayer.Config

                    new Client
                    {
                        ClientId = _configurationManager.Value.ClientId,
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, //основной сценарий входа
                        RequireClientSecret = false, //Client Secret в браузере не понадобится, выключаем
                        AllowedScopes = { _configurationManager.Value.ApiName,
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile},//для получения инфы о пользователе по /connect/userinfo
                        AllowOfflineAccess = true //включает рефреш-токен
                    }
    

    Далее этого клиента сидируем в базу при ее создании:

    TestIdentityServer.Program

    services.GetRequiredService<DbInitializer>().Initialize();
    

    В методе «Initialize» добавлен код для создания необходимых баз и инсерта данных, в том числе клиента. Но до этого необходимо выполнить миграции, потому что создать придется базу из 3х контекстов, где первый контекст IdentityDbContext ApplicationUser, а остальные для IdentityServer4:

    DataLayer.DbInitializer

                _context.Database.Migrate();
                _configurationDbContext.Database.Migrate();
                _persistedGrantDbContext.Database.Migrate();
    

                if (!_configurationDbContext.Clients.Any())
                {
                    foreach (var client in _config.GetClients().ToList())
                    {
                        _configurationDbContext.Clients.Add(client.ToEntity());
                    }
                    _configurationDbContext.SaveChanges();
                }
    

    Миграции:

    dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
    
    dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
    
    dotnet ef migrations add InitialAuthMigration -c AuthContext -o Data/Migrations/IdentityServer/Auth
    

    Ссылка на код будет в конце.

    Идем дальше. После задания клиента и создания базы сервер может уже обрабатывать запросы "/connect/token" по логину с паролем и выдавать access_token с refresh_token.
    По нему же, с указанием refresh_token, обновить их.

    Логин пароль:

    image

    refresh_token

    image

    /connect/userinfo

    image

    Теперь добавим апи которое будет авторизироваться у IdentityServer4. Его связь с ним будет осуществляться так:

    DataApi.Startup

                services.AddAuthentication("Bearer")
                    .AddIdentityServerAuthentication(options =>
                    {
                        options.Authority = settings.Authority; //Адресс сервера http://localhost:5000
                        options.RequireHttpsMetadata = false;
                        options.ApiName = settings.ApiName;//api1
                    });
    

    Само апи будет развернуто на другом порту.

    Авторизация теперь будет проверяться как обычно атрибутом "[Authorize]".

    /api/Default

    image



    На этом все, пишите кто че думает или чего не хватает.

    Ссылка на код.

    UPD: Подпись jwt токенов

    Добавил способы подписи: RSA который генерируется при старте и *.pfx файл сертификата. Соответствующий метод можно переключить в «appsettings.json», свойство «SigningCredentialConfig».
    • +23
    • 4,5k
    • 6
    Поделиться публикацией
    Комментарии 6
      +1

      Вы ведь подписываете jwt токены?


      В целом, неплохо бы чек-лист, что нужно проверить и настроить для работы identityserver4 в интернете в production режиме.

        0
        Ага,
        builder.AddDeveloperSigningCredential();

        на выходе дает «alg»: «RS256». Вообще можно свой RsaSecurityKey в AddSigningCredential передать, либо сделать сертификат, если нужно постоянство открытого ключа. У меня до idsrv4 был симметричный алгоритм для jwt. Токен живет недолго, потом обновляется и в браузере проверять подпись не надо, главное чтоб https было. Поправьте если ошибаюсь.
        +1

        и не забывать делать token/revocationn, а то таблица PersistedGrants быстро наполняется и потом больно будет.

          0
          token/revocation — это же отзыв токена? Сейчас залез в PersistedGrants, там уже больше 7к записей. Не так много, но еще тестовая эксплуатация. Что с ними делать, как автоматизировать чистку?
            0
            ну вы же в коде получаете токен. и используете его. в конце, при завершении использования надо делать revocation для этого токена. и тогда он будет зачищаться в этой таблице.
            если руками удалить все записи из таблицы PersistedGrants — то не сможете потом залогиниться ((((
            там можно для каждого токена удалять всё, кроме последней записи (последней по времени) — мы так вручную вынуждены были зачищать токены.

            «уже больше 7к записей» — вот у нас их было более 100к и всё стало очень тормозить. всё это я про получение токена.
          –1
          Как на счет краткого бекграунда? Кто такой рифреш токен? Клиент? Почему connect/token? Не знал бы темы, ничего бы не понял из написанного.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое