Spring Security — пример REST-сервиса с авторизацией по протоколу OAuth2 через BitBucket и JWT / Хабр

Введение в аутентификацию и авторизацию

Аутентификация и авторизация в Web API имеет некоторые особенности в отличие от ASP.NET MVC. Здесь фактически нам доступны три вида аутентификации:
стандартная через куки, через внешние сервисы и аутентификация с помощью токена.

В то же время Web API и ASP.NET MVC имеют ряд общих моментов.

Авторизация под разными рабочими аккаунтами

Для получения списка рабочих аккаунтов менеджера и для работы под разными рабочими аккаунтами менеджера необходимо прочитать документацию по рабочим аккаунтам менеджера

Вход в систему

Метод идентифицирует пользователя по переданным email и паролю и если все в порядке, генерирует токен доступа, устанавливает дату действия токена и возвращает его в json.

Выход из системы

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

Запрос авторизации под другим пользователем

Возможен следующий сценарий:

  1. Приложение перенаправляет пользователя на сайт с запросом авторизации.
  2. Пользователь на сайте уже авторизован и данному приложение доступ уже был
    разрешен.
  3. Пользователю будет предложена возможность продолжить работу под текущим аккаунтом,
    либо зайти под другим аккаунтом.

Если есть необходимость, чтобы на шаге 3 сразу происходило перенаправление (redirect) с временным токеном,
необходимо добавить к запросу /oauth/authorize… параметр skip_choose_account=true.
В этом случае автоматически выдаётся доступ пользователю авторизованному на сайте.

Инвалидация access-токена

Для того, чтобы инвалидировать текущий access-токен, необходимо сделать запрос:

Передавая его стандартным способом в заголовке в формате:

Authorization: Bearer ACCESS_TOKEN

Инвалидация работает только на действующем access-токене.

После инвалидации токен нельзя будет запросить с помощью refresh-токена – для работы необходимо будет заново авторизоваться в api.

Таким образом можно инвалидировать только токен пользователя.

Исходный код

Полный исходный код рассмотренного приложения находится на

Маршруты для аутентификации

После реализации методов контроллера аутентификации создадим соответствующие маршруты в файле /routes/api.php:

Route::group(['namespace' => 'Api'], function () {
	Route::post('register', 'AuthController@register');
	Route::post('login', 'AuthController@login');
	Route::post('logout', 'AuthController@logout')->middleware('auth:api');
});

Два первых маршрута – register и login работают для неавторизованных пользователей. Третий маршрут logout работает через middleware auth – только для авторизованных пользователей. Для запросов по этому маршруту следует передавать в запросе заголовок с токеном доступа:

Authorization: Bearer erJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9…

Теперь все готово. Можно регистрировать нового пользователя через вызов /api/register, передав параметры name, email и password, авторизоваться через вызов /api/login, передав email и password, и выходить из системы через вызов /api/logout.

Настроим spring security

Соберем все проделанное выше вместе и настроим Spring Security.

Немного теории

Аутентификация

Обновление пары access и refresh токенов

access_token также имеет срок жизни (ключ expires_in, в секундах), при его
истечении приложение должно сделать запрос с refresh_token для получения
нового.

Запрос необходимо делать в application/x-www-form-urlencoded.

В теле запроса необходимо передать дополнительные параметры:

Ответ

Ответ будет идентичен ответу на получения токенов в первый раз:

refresh_token можно использовать только один раз и только по истечению
срока действия access_token.

После получения новой пары access и refresh токенов, их необходимо использовать
в дальнейших запросах в api и запросах на продление токена.

Ошибки

  • 400 Bad Request – ошибка в параметрах запроса.

Переопределим authenticationfailurehandler

В случае, если пользователь не прошел аутентификацию, мы перенаправим его по адресу обратного вызова, который был передан в начале процесса аутентификации с параметром error, содержащим текст ошибки.

ExampleAuthenticationFailureHandler

public class ExampleAuthenticationFailureHandler implements AuthenticationFailureHandler {

    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    private final HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository;

    public ExampleAuthenticationFailureHandler(
            HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository) {
        this.authorizationRequestRepository = requireNonNull(authorizationRequestRepository);
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
        String targetUrl = getFailureUrl(request, exception);
        authorizationRequestRepository.removeAuthorizationRequestCookies(request, response);
        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    private String getFailureUrl(HttpServletRequest request, AuthenticationException exception) {
        String targetUrl = getCookie(request, Cookies.REDIRECT_URI)
                .map(Cookie::getValue)
                .orElse(("/"));

        return UriComponentsBuilder.fromUriString(targetUrl)
                .queryParam("error", exception.getLocalizedMessage())
                .build().toUriString();
    }
}

Получение авторизации пользователя

В начале приложению необходимо направить пользователя (открыть страницу) по адресу:

Обязательные параметры:

  • response_type=code — указание на способ получения авторизации, используя authorization code
  • client_id — идентификатор, полученный при создании приложения

Необязательные параметры:

Процесс авторизации

Если пользователь не авторизован на сайте, ему будет показана форма
авторизации на сайте. После прохождения авторизации на сайте, пользователю
будет выведена форма с запросом разрешения доступа вашего приложения к его
персональным данным.

Если пользователь не разрешает доступ приложению, пользователь будет
перенаправлен на указанный redirect_uri с ?error=access_denied и
state={state}, если таковой был указан при первом запросе.

Если пользователь авторизован, ему будет показана форма для подтверждения работы под текущим пользователем или смены пользователя.

Реализация

Мы реализуем REST-сервис, предоставляющий следующее API:

Spring Security — пример REST-сервиса с авторизацией по протоколу OAuth2 через BitBucket и JWT / ХабрВысокоуровневая архитектура приложения

Заметим, что поскольку приложение состоит из трех взаимодействующих компонентов, помимо того, что мы выполняем авторизацию запросов клиента к серверу, Bitbucket авторизует запросы сервера к нему. Мы не будем настраивать авторизацию методов по ролям, чтобы не делать пример сложнее.

Spring Security — пример REST-сервиса с авторизацией по протоколу OAuth2 через BitBucket и JWT / Хабр
Процесс регистрации OAuth клиента описан в предыдущей статье

Для реализации мы будем использовать Spring Boot версии 2.2.2.RELEASE и Spring Security версии 5.2.1.RELEASE.

Регистрация пользователя

В этом методе создается объект пользователя по переданным параметрам (имя, email, пароль), сохраняется в БД и возвращается сообщение об у спешной регистрации.

Создадим tokenauthenticationfilter

Задача этого фильтра извлечь токен доступа из заголовка Authorization в случае его наличия, провалидировать его и инициализировать секьюрити контекст.

Ссылки


P.S.

Успешное получение временного authorization_code

В случае разрешения прав, в редиректе будет указан
временный authorization_code:

Создадим repositories endpoint

То ради чего и нужна была аутентификация через OAuth2 и Bitbucket — возможность использовать Bitbucket API для доступа к своим ресурсам. Используем Bitbucket repositories API для получения списка репозиториев текущего пользователя.

Создадим login endpoint

Для аутентификации пользователя мы по-прежнему используем OAuth2 с типом авторизации Authorization Code. Однако на предыдущем шаге мы заменили стандартный AuthenticationEntryPoint своей реализацией, поэтому нам нужен явный способ запустить процесс аутентификации.

Похожее:  Личный кабинет Ланта: регистрация, официальный сайт

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *