Тут не будет ничего необычного, один фреймворк «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

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

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

Комментарии (2)


  1. easyman
    13.10.2018 21:27

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


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


  1. onatsko
    14.10.2018 11:03

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