Spring Security with OAuth2 Login Guide – amitph

4. Что поддерживает Jakarta EE?

Пока не очень много. В этом уроке мы построим большинство вещей с нуля.

Обзор

В этом учебном пособии мы представим реализацию платформы авторизации OAuth 2.0 с использованием Jakarta EE и МикроПрофиля. Самое главное, мы собираемся реализовать взаимодействие ролей OAuth 2.0 через Тип предоставления кода авторизации .

Для наиболее важной роли, сервера авторизации, мы собираемся реализовать Конечную точку авторизации, Конечную точку токена и, кроме того , конечную точку ключа JWK , которая полезна серверу ресурсов для извлечения открытого ключа.

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

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

Oauth2 Authorization Server With Spring Boot

Let’s setup an authorization server to enable Oauth2 with Spring Boot. We have the option to create the application using IDE (like IntelliJ IDEA) or we can create an application using Spring Boot CLI.

$ spring init --dependencies=web,actuator my-project

If you prefer a more visual interface to generate an initial structure, we can use the Spring Initializer:

Click on the “Generate” button to download the project on your local machine.We selected the following dependencies for our application:

  1. Web starter 

To enable the Oauth support, add the following dependency in the pom.xml file:

This dependency will add all the prerequisite to use Oauth2 features for our application. The next step is to add some configurations for our application. Add the following entry to the src/main/resources/application.properties file:

Обзор OAuth 2.0

В этом разделе мы дадим краткий обзор ролей OAuth 2.0 и потока предоставления кода авторизации.

1. Роли

Платформа OAuth 2.0 подразумевает сотрудничество между четырьмя следующими ролями:

  • Владелец ресурса : Обычно это конечный пользователь-это организация, у которой есть некоторые ресурсы, которые стоит защищать
  • Сервер ресурсов : служба, которая защищает данные владельца ресурса, обычно публикуя их через API REST
  • Клиент : Приложение, которое использует данные владельца ресурса
  • Сервер авторизации : приложение, которое предоставляет разрешение – или полномочия – клиентам в виде истекающих токенов

2. Типы Разрешений

Тип предоставления – это способ, с помощью которого клиент получает разрешение на использование данных владельца ресурса, в конечном счете, в виде токена доступа.

Естественно, разные типы клиентов предпочитают разные типы грантов :

  • Код авторизации : Предпочтительнее всего является ли это веб-приложением, собственным приложением или одностраничным приложением , хотя собственные и одностраничные приложения требуют дополнительной защиты, называемой PKCE
  • Токен обновления : Специальный грант на продление, подходящий для веб-приложений для обновления существующего токена
  • Учетные данные клиента : Предпочтительно для связи между службами , скажем, когда владелец ресурса не является конечным пользователем
  • Владелец ресурсаПароль : Предпочтительно для сторонней аутентификации собственных приложений, скажите, когда мобильному приложению нужна собственная страница входа

Кроме того, клиент может использовать тип неявный грант. Однако, как правило, более безопасно использовать предоставление кода авторизации с помощью PKCE.

3. Поток Предоставления Кода Авторизации

Поскольку поток предоставления кода авторизации является наиболее распространенным, давайте также рассмотрим, как это работает, и это на самом деле то, что мы создадим в этом руководстве.

Приложение – клиент – запрашивает разрешение путем перенаправления на конечную точку/авторизациисервера авторизации. Этой конечной точке приложение выдает обратный вызов конечной точке.

Сервер авторизации обычно запрашивает разрешение у конечного пользователя-владельца ресурса. Если конечный пользователь предоставляет разрешение, то сервер авторизации перенаправляет обратно на обратный вызов с кодом .

Приложение получает этот код, а затем выполняет аутентифицированный вызов/маркераконечной точки сервера авторизации. Под “аутентификацией” мы подразумеваем, что приложение доказывает, кто оно в рамках этого вызова. Если все отображается в порядке, сервер авторизации отвечает маркером.

С токеном в руке приложение делает запрос к API – серверу ресурсов – и этот API проверит токен. Он может попросить сервер авторизации проверить токен, используя свою конечную точку /introspect . Или, если токен является автономным, сервер ресурсов может оптимизировать работу, локально проверив подпись токена, как в случае с JWT.

Resource Server

Now we’ll create a resource server that will return a list of articles from a GET endpoint. The endpoints should allow only requests that are authenticated against our OAuth server.

Сервер авторизации OAuth 2.0

В этой реализации мы сосредоточимся на наиболее часто используемом типе предоставления : Код авторизации.

1. Obtaining Client Credentials

To obtain client credentials for Google OAuth2 authentication, head on over to the Google API Console, “Credentials” section.

Here we’ll create credentials of type “OAuth2 Client ID” for our web application. This results in Google setting up a client id and secret for us.

1. Providers

Spring defines the OAuth2 Provider role responsible for exposing OAuth 2.0 protected resources.

In our example, our Authentication Service will be the one offering the Provider capabilities.

1. Регистрация Клиента и Пользователя

Сервер авторизации, конечно, должен был бы знать о клиентах и пользователях, прежде чем он сможет авторизовать их запросы. И для сервера авторизации обычно требуется пользовательский интерфейс для этого.

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

И предварительно настроенный пользователь:

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

В остальной части этого урока мы покажем, как пользователь приложения – владелец ресурса – может предоставить доступ к webappclient – приложению – путем реализации Кода авторизации.

2. Client Registrations

A ClientRegistration is an entity containing all the relevant information of a specific client registered in an OAuth2 (or an OpenID) provider.

In our scenario, it’ll be the client registered in the Authentication Server, identified by the bael-client-id id.

2. Конечная точка авторизации

Основная роль конечной точки авторизации состоит в том, чтобы сначала аутентифицировать пользователя, а затем запросить разрешения – или области–, которые нужны приложению.

3. Articles Controller

Finally, we’ll create a REST controller that will return a list of articles under the GET /articles endpoint:

@RestController
public class ArticlesController {

    @GetMapping("/articles")
    public String[] getArticles() {
        return new String[] { "Article 1", "Article 2", "Article 3" };
    }
}

4. Конечная точка токена

В отличие от конечной точки авторизации, конечной точке токена не нужен браузер для связи с клиентом , и поэтому мы реализуем ее как конечную точку JAX-RS:

Для конечной точки токена требуется сообщение, а также кодирование параметров с использованием application/x-www-форма-url-кодированный тип носителя.

Как мы уже обсуждали, мы будем поддерживать только код авторизации тип гранта:

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

5. Закрытые и открытые ключи RSA

Перед созданием токена нам нужен закрытый ключ RSA для подписи токенов.

Для этой цели мы будем использовать OpenSSL:

Закрытый ключ.pem предоставляется серверу через конфигурацию микропрофиля ключ подписи свойство с использованием файла META-INF/microprofile-config.properties:

Сервер может прочитать свойство, используя введенный Config объект:

Аналогично, мы можем сгенерировать соответствующий открытый ключ:

И используйте конфигурацию микропрофиля Ключ проверки , чтобы прочитать его:

Сервер должен сделать его доступным для сервера ресурсов для цели проверки. Это делается через конечную точку JWK.

Nimbus JOSE JWT – это библиотека, которая может оказать здесь большую помощь. Давайте сначала добавим | нимбус-хосе-jwt зависимость :

И теперь мы можем использовать поддержку JWK Nimbus для упрощения нашей конечной точки:

Мы использовали параметр format для переключения между форматами PEM и JWK. Микропрофиль JWT, который мы будем использовать для реализации сервера ресурсов, поддерживает оба этих формата.

6. Ответ Конечной Точки Токена

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

Для создания токена в этом формате мы снова будем использоватьNimbus JOSE JWTбиблиотека , но есть множество других библиотек JWT .

Итак, чтобы создать подписанный JWT, сначала нам нужно создать заголовок JWT:

Затем мы создаем полезную нагрузку , которая представляет собой Набор стандартизированных и пользовательских утверждений:

В дополнение к стандартным утверждениям JWT мы добавили еще два утверждения – upn и группы – по мере необходимости для JWT микропрофиля. upn будет сопоставлен с безопасностью Jakarta EE Принципал вызывающего абонента и группы будут сопоставлены с Jakarta EE Роли.

Теперь, когда у нас есть заголовок и полезная нагрузка, нам нужно подписать маркер доступа закрытым ключом RSA . Соответствующий открытый ключ RSA будет предоставлен через конечную точку JWK или станет доступным другими способами, чтобы сервер ресурсов мог использовать его для проверки маркера доступа.

Поскольку мы предоставили закрытый ключ в формате PEM, мы должны извлечь его и преобразовать в RSAPrivateKey:

Далее, мы подписываем и сериализуем JWT:

И, наконец, мы создаем ответный токен:

который, благодаря JASON-P, сериализуется в формат JSON и отправляется клиенту:

Testing Application

In the first part of the testing, I will use Postman. When any third party try to access the customer profile data, that service need oauth2 token.

Клиент OAuth 2.0

В этом разделе мы будем создавать веб-клиент OAuth 2.0 с использованием сервлета, Конфигурации микропрофиля и клиентских API JAX RS.

Точнее, мы будем реализовывать два основных сервлета: один для запроса конечной точки авторизации сервера авторизации и получения кода с использованием типа предоставления кода авторизации, а другой сервлет для использования полученного кода и запроса маркера доступа с конечной точки маркера сервера авторизации.

Кроме того, мы будем реализовывать еще два сервлета: один для получения нового маркера доступа с использованием типа предоставления маркера обновления, а другой для доступа к API сервера ресурсов.

1. Сведения о клиенте OAuth 2.0

Поскольку клиент уже зарегистрирован на сервере авторизации, нам сначала необходимо предоставить регистрационную информацию о клиенте:

  • client_id: Идентификатор клиента, который обычно выдается сервером авторизации в процессе регистрации.
  • client_secret: Секрет клиента.
  • redirect_uri: Место, где можно получить код авторизации.
  • область действия: Запрошенные клиентом разрешения.

Кроме того, клиент должен знать конечные точки авторизации и токенов сервера авторизации:

  • authorization_uri: Расположение конечной точки авторизации сервера авторизации, которую мы можем использовать для получения кода.
  • token_uri: Местоположение конечной точки маркера сервера авторизации, которую мы можем использовать для получения маркера.

Вся эта информация предоставляется через конфигурационный файл микропрофиля, META-INF/microprofile-config.properties:

2. Building ClientRegistration Objects

Let’s see the getRegistration() method that builds these objects:

2. Configuration

As we did earlier, we’ll define some configuration properties for authentication purposes:

2. Запрос Кода Авторизации

Процесс получения кода авторизации начинается с клиента путем перенаправления браузера на конечную точку авторизации сервера авторизации.

Как правило, это происходит, когда пользователь пытается получить доступ к API защищенного ресурса без авторизации или явно путем вызова клиента /авторизация путь:

В методе doGet() мы начинаем с создания и сохранения значения состояния безопасности:

Затем мы получаем информацию о конфигурации клиента:

Затем мы добавим эти фрагменты информации в качестве параметров запроса к конечной точке авторизации сервера авторизации:

И, наконец, мы перенаправим браузер на этот URL:

3. Запрос токена Доступа

Сервлет обратного вызова клиента, /обратный вызов, начинается с проверки принятого состояния:

Затем мы будем использовать полученный ранее код для запроса маркера доступа через конечную точку маркера сервера авторизации:

4. Защищенный Доступ К Ресурсам

На данный момент у нас есть действительный токен доступа, и мы можем вызвать сервер ресурсов/ читать и/ писать АПИС.

Для этого мы должны предоставитьАвторизациюзаголовок . Используя клиентский API JAX-RS, это просто делается с помощью вызова .Заголовок конструктора() метод:

Spring Security 5 Support – Implementation Using the Authorization Code Flow

This grant type is usually used in cases where less-trusted third-party applications need to access resources.

Сервер ресурсов OAuth 2.0

В этом разделе мы будем создавать защищенное веб-приложение на основе JAX-RS, JWT микропрофиля и конфигурации микропрофиля. Микропрофиль JWT заботится о проверке полученных JWT и сопоставлении областей JWT с ролями Jakarta EE .

1. Custom Login Page

Even though Spring Boot generates a default login page for us, we’ll usually want to define our own customized page.

Let’s start with configuring a new login URL for the oauth2Login() element by using theloginPage() method:

1. Зависимости Maven

В дополнение к зависимости Java EE Web API нам также нужны Конфигурация микропрофиля и JWT микропрофиля API:

2. Custom Authentication Success and Failure Behavior

We can control the post-authentication behavior with different methods:

2. Механизм аутентификации JWT

Микропрофиль JWT обеспечивает реализацию механизма аутентификации токенов на предъявителя. Это обеспечивает обработку JWT, присутствующего в заголовке Authorization , делает доступным принципала безопасности Jakarta EE в качестве JsonWebToken , который содержит утверждения JWT, и сопоставляет области с ролями Jakarta EE. Взгляните на Jakarta EE Security API для получения дополнительной информации.

Чтобы включить Механизм аутентификации JWT на сервере, нам нужно добавитьКонфигурацию входааннотацию в приложение JAX-RS:

Кроме того, МикроПрофиль JWT нуждается в открытом ключе RSA для проверки подписи JWT . Мы можем обеспечить это либо путем самоанализа, либо, для простоты, вручную скопировав ключ с сервера авторизации. В любом случае нам необходимо указать местоположение открытого ключа:

Наконец, JWT микропрофиля должен проверить утверждение isis входящего JWT, которое должно присутствовать и соответствовать значению свойства конфигурации МикроПрофиля:

Как правило, это местоположение Сервера авторизации.

3. Configuring the WebClient

Now it’s time to put our WebClient instance in place:

@Bean
WebClient webClient(
  ReactiveClientRegistrationRepository clientRegistrations,
  ServerOAuth2AuthorizedClientRepository authorizedClients) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
      new ServerOAuth2AuthorizedClientExchangeFilterFunction(
        clientRegistrations,
        authorizedClients);
    oauth.setDefaultOAuth2AuthorizedClient(true);
    return WebClient.builder()
      .filter(oauth)
      .build();
}

3. Защищенные Конечные Точки

В демонстрационных целях мы добавим API ресурсов с двумя конечными точками. Одним из них является конечная точка чтение , доступная пользователям, имеющим область resource.read , и другая конечная точка запись для пользователей с областью resource.write .

Ограничение областей действия выполняется с помощью @RolesAllowed аннотации:

Запуск Всех Серверов

Чтобы запустить один сервер, нам просто нужно вызвать команду Maven в соответствующем каталоге:

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

Итак, мы можем получить доступ к домашней странице клиента, а затем нажать “Получить токен доступа”, чтобы запустить процесс авторизации. После получения маркера доступа мы можем получить доступ к API чтения и записи сервера ресурсов.

About authlete

Authlete is a cloud service that provides an implementation of OAuth 2.0
& OpenID Connect (overview). You can easily get the functionalities of
OAuth 2.0 and OpenID Connect either by using the default implementation
provided by Authlete or by implementing your own authorization server using
Authlete Web APIs as this implementation (java-oauth-server) does.

To use this authorization server implementation, you need to get API credentials
from Authlete and set them in authlete.properties. The steps to get API
credentials are very easy. All you have to do is just to register your account
(sign up). See Getting Started for details.

Authorization request example

The following is an example to get an access token from the authorization
endpoint using Implicit Flow. Don’t forget to replace {client-id} in
the URL with the real client ID of one of your client applications. As for
client applications, see Getting Started and the document of
Developer Console.

The request above will show you an authorization page. The page asks you to
input login credentials and click “Authorize” button or “Deny” button. Use
one of the following as login credentials.

Login IDPassword
johnjohn
janejane
maxmax
ingainga

Configuration file

java-oauth-server refers to authlete.properties as a configuration file.
If you want to use another different file, specify the name of the file by
the system property authlete.configuration.file like the following.

Custom login success/failure pages

We can add our own pages, which can be displayed upon a successful login or an unsuccessful login. To do so, can use defaultSuccessUrl(url) and failureUrl(url) methods on OAuth2LoginConfigurer.

Configuring oauth2Login() to dispaly custom Success/Failure Pages

Code language:Java(java)

Additionally, we can also invoke some code upon a successful or failed login. To do that we need to use successHandler() and failureHandler() methods providing implementations for AuthenticationSuccessHandler and AuthenticationFailureHandler respectively.

Implementation note

This implementation uses Viewable class to implement the authorization page.
The class is included in Jersey (the reference implementation of JAX-RS),
but it is not a part of JAX-RS 2.0 API.

License

Apache License, Version 2.0

Overview

This is an authorization server implementation in Java which supports
OAuth 2.0 and OpenID Connect.

This implementation is written using JAX-RS 2.0 API and authlete-java-jaxrs
library. JAX-RS is The Java API for RESTful Web Services. JAX-RS 2.0 API has
been standardized by JSR 339 and it is included in Java EE 7.

On the other
hand, authlete-java-jaxrs library is an open source library which provides utility
classes for developers to implement an authorization server and a resource server.
authlete-java-jaxrs in turn uses authlete-java-common library which is
another open source library to communicate with Authlete Web APIs.

This implementation is DB-less. What this means is that you don’t have to
have a database server that stores authorization data (e.g. access tokens),
settings of the authorization server itself and settings of client applications.
This is achieved by using Authlete as a backend service.

Access tokens issued by this authorization server can be used at a resource
server which uses Authlete as a backend service. java-resource-server
is such a resource server implementation. It includes an example implementation
of protected resource endpoint.

Run with docker

If you would prefer to use Docker, just hit the following command after the step 2.

Setup

For this tutorial we will need a Spring or Spring Boot Application upon which we will enable the Spring Security OAuth2 Login. To quickly bootstrap a Spring Boot application from scratch refer to Create a Spring Boot REST Service article.

Spring (non spring boot) security configuration

On the other hand, in Non Spring Boot Spring projects we do not get the auto configuration support. Thus first we need to enable Spring Security by adding @EnableWebSecurity and create a ClientRegistrationRepository.

Create ClientRegistrationRepository

Code language:Java(java)

Spring boot security configuration

In order to enable Spring Security OAuth2 Login within a Spring Boot application it needs ‘spring-boot-starter-oauth2-client’ dependency and provide at least one client credentials. Spring boot auto configuration sets up Oauth2ClientAutoConfiguration instance, which is responsible for enabling required configurations.

Spring boot dependency

On the other hand, for Spring Boot applications we only need Spring Security OAuth2 Client dependency.

Code language:HTML, XML(xml)

Also, we do not need to provide the version explicitly. That is because, Spring Boot dependency manager implicitly takes care of the versions.

3. Custom Authorization Endpoint

The authorization endpoint is the endpoint that Spring Security uses to trigger an authorization request to the external server.

First, let’s set new properties for the authorization endpoint:

.oauth2Login() 
  .authorizationEndpoint()
  .baseUri("/oauth2/authorize-client")
  .authorizationRequestRepository(authorizationRequestRepository());

Here we’ve modified the baseUri to /oauth2/authorize-client instead of the default /oauth2/authorization.

We’re also explicitly setting an authorizationRequestRepository() bean that we have to define:

5. Custom Redirection Endpoint

This is the endpoint to redirect to after authentication with the external provider.

Let’s see how we can change the baseUri for the redirection endpoint:

.oauth2Login()
  .redirectionEndpoint()
  .baseUri("/oauth2/redirect")

The default URI is login/oauth2/code.

Note that if we change it, we also have to update the redirectUriTemplate property of each ClientRegistration and add the new URI as an authorized redirect URI for each client.

Conclusion

In this article, we learned how to set up our application as an OAuth2 Client, and more specifically, how we can configure and use the WebClient to retrieve a secured resource in a full-reactive stack.

Then we analyzed how Spring Security 5 OAuth2 mechanisms operate under the hood to comply with the OAuth2 specification.

As always, the full example is available over on Github.

1. Dependencies

First, we’ll need to add a few dependencies to our pom.xml file:

Endpoints

This implementation exposes endpoints as listed in the table below.

The authorization endpoint and the token endpoint accept parameters described
in RFC 6749, OpenID Connect Core 1.0,
OAuth 2.0 Multiple Response Type Encoding Practices, RFC 7636
(PKCE) and other specifications.

The JWK Set endpoint exposes a JSON Web Key Set document (JWK Set) so that
client applications can (1) verify signatures by this OpenID Provider and
(2) encrypt their requests to this OpenID Provider.

The configuration endpoint exposes the configuration information of this
OpenID Provider in the JSON format defined in OpenID Connect Discovery 1.0.

The revocation endpoint is a Web API to revoke access tokens and refresh
tokens. Its behavior is defined in RFC 7009.

The introspection endpoint is a Web API to get information about access
tokens and refresh tokens. Its behavior is defined in RFC 7662.

1. Dependencies

First, we’ll include the required dependencies:

1. Dependencies

To start, we’ll include the necessary dependencies:

Заключение

В этой статье мы представили реализацию сервера авторизации OAuth 2.0, который можно использовать с любым совместимым клиентом OAuth 2.0 и сервером ресурсов.

Чтобы объяснить общую структуру, мы также предоставили реализацию для клиента и сервера ресурсов. Для реализации всех этих компонентов мы использовали API Jakarta EE 8, особенно CDI, сервлет, JAX RS, безопасность Jakarta EE. Кроме того, мы использовали псевдо-джакартские API EE для микропрофиля: Конфигурация микропрофиля и JWT микропрофиля.

Полный исходный код примеров доступен на GitHub . Обратите внимание, что код содержит пример как кода авторизации, так и типов предоставления токенов обновления.

Наконец, важно помнить об образовательном характере этой статьи и о том, что приведенный пример не следует использовать в производственных системах.

Spring (non spring boot) dependency

If you have a Spring non-boot application, you need to add next two dependencies in your Maven configuration.

Code language:HTML, XML(xml)

As this tutorial is based on Spring Security 5, add the latest versions of the these dependencies from here and here.

Похожее:  Вход в личный кабинет Tiande — полное руководство по доступу к аккаунту Tiande

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

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