Перейти к основному содержимому

Весенняя безопасность с Auth0

· 9 мин. чтения

1. Обзор

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

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

2. Настройка Auth0

2.1. Auth0 Регистрация

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

./add818be5bf966de0c052dbfb5a38cb7.png

2.2. Приборная доска

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

./b1f86a81f78fc16a54068a7f9c644de3.png

2.3. Создать новое приложение

Затем в меню «Приложения» мы создадим новое приложение OpenID Connect (OIDC) для Spring Boot .

Кроме того, мы выберем обычные веб-приложения в качестве типа приложения из доступных вариантов, таких как Native , Single-Page Apps и Machine to Machine Apps :

./a4abf2ed29f1287c2a3e13720698b29b.png

2.4. Настройки приложения

Далее мы настроим несколько URI приложений , таких как URL- адреса обратного вызова и URL -адреса выхода , указывающие на наше приложение:

./8de36c1e8ad78b14c5ce30e0643cbd37.png

2.5. Учетные данные клиента

Наконец, мы получим значения домена , идентификатора клиента и секрета клиента , связанные с нашим приложением:

./52e5cbe15935a082cd56aaf0731579fd.png

Держите эти учетные данные под рукой, потому что они необходимы для настройки Auth0 в нашем приложении Spring Boot.

3. Настройка приложения Spring Boot

Теперь, когда наша учетная запись Auth0 готова с ключевыми конфигурациями, мы готовы интегрировать безопасность Auth0 в приложение Spring Boot.

3.1. Мавен

Во-первых, давайте добавим последнюю зависимость mvc-auth-commons Maven к нашему pom.xm l:

<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>1.2.0</version>
</dependency>

3.2. Грейдл

Точно так же при использовании Gradle мы можем добавить зависимость mvc-auth-commons в файл build.gradle :

compile 'com.auth0:mvc-auth-commons:1.2.0'

3.3. приложение.свойства

Нашему приложению Spring Boot требуется такая информация, как идентификатор клиента и секрет клиента , чтобы включить аутентификацию учетной записи Auth0. Итак, добавим их в файл application.properties :

com.auth0.domain: dev-example.auth0.com
com.auth0.clientId: {clientId}
com.auth0.clientSecret: {clientSecret}

3.4. Аутконфиг

Далее мы создадим класс AuthConfig для чтения свойств Auth0 из файла application.properties :

@Configuration
@EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Value(value = "${com.auth0.domain}")
private String domain;

@Value(value = "${com.auth0.clientId}")
private String clientId;

@Value(value = "${com.auth0.clientSecret}")
private String clientSecret;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/callback", "/login", "/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler()).permitAll();
}
}

Кроме того, класс AuthConfig настроен для включения веб-безопасности путем расширения класса WebSecurityConfigurerAdapter .

3.5. Контроллер аутентификации

Наконец, мы добавим ссылку на компонент для класса AuthenticationController в уже обсуждаемый класс AuthConfig :

@Bean
public AuthenticationController authenticationController() throws UnsupportedEncodingException {
JwkProvider jwkProvider = new JwkProviderBuilder(domain).build();
return AuthenticationController.newBuilder(domain, clientId, clientSecret)
.withJwkProvider(jwkProvider)
.build();
}

Здесь мы использовали класс JwkProviderBuilder при создании экземпляра класса AuthenticationController . Мы будем использовать это для получения открытого ключа для проверки подписи токена (по умолчанию токен подписывается с использованием алгоритма асимметричной подписи RS256).

Кроме того, bean- компонент authenticationController предоставляет URL-адрес авторизации для входа в систему и обрабатывает запрос обратного вызова.

4. Контроллер авторизации

Далее мы создадим класс AuthController для функций входа и обратного вызова:

@Controller
public class AuthController {
@Autowired
private AuthConfig config;

@Autowired
private AuthenticationController authenticationController;
}

Здесь мы внедрили зависимости классов AuthConfig и AuthenticationController , которые обсуждались в предыдущем разделе.

4.1. Авторизоваться

Давайте создадим метод входа в систему , который позволяет нашему приложению Spring Boot аутентифицировать пользователя:

@GetMapping(value = "/login")
protected void login(HttpServletRequest request, HttpServletResponse response) {
String redirectUri = "http://localhost:8080/callback";
String authorizeUrl = authenticationController.buildAuthorizeUrl(request, response, redirectUri)
.withScope("openid email")
.build();
response.sendRedirect(authorizeUrl);
}

Метод buildAuthorizeUrl создает URL-адрес авторизации Auth0 и перенаправляет на экран входа Auth0 по умолчанию.

4.2. Перезвонить

Как только пользователь войдет в систему с учетными данными Auth0, запрос обратного вызова будет отправлен в наше приложение Spring Boot. Для этого создадим метод обратного вызова :

@GetMapping(value="/callback")
public void callback(HttpServletRequest request, HttpServletResponse response) {
Tokens tokens = authenticationController.handle(request, response);

DecodedJWT jwt = JWT.decode(tokens.getIdToken());
TestingAuthenticationToken authToken2 = new TestingAuthenticationToken(jwt.getSubject(),
jwt.getToken());
authToken2.setAuthenticated(true);

SecurityContextHolder.getContext().setAuthentication(authToken2);
response.sendRedirect(config.getContextPath(request) + "/");
}

Мы обработали запрос обратного вызова, чтобы получить accessToken и idToken , которые представляют собой успешную аутентификацию. Затем мы создали объект TestingAuthenticationToken для установки аутентификации в SecurityContextHolder .

Однако мы можем создать нашу реализацию класса AbstractAuthenticationToken для большего удобства использования.

5. Домашний контроллер

Наконец, мы создадим HomeController с сопоставлением по умолчанию для нашей целевой страницы приложения:

@Controller
public class HomeController {
@GetMapping(value = "/")
@ResponseBody
public String home(final Authentication authentication) {
TestingAuthenticationToken token = (TestingAuthenticationToken) authentication;
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
String email = jwt.getClaims().get("email").asString();
return "Welcome, " + email + "!";
}
}

Здесь мы извлекли объект DecodedJWT из idToken . Кроме того, информация о пользователе, такая как электронная почта, извлекается из заявок.

Вот и все! Наше приложение Spring Boot готово с поддержкой безопасности Auth0. Давайте запустим наше приложение с помощью команды Maven:

mvn spring-boot:run

При доступе к приложению по адресу localhost:8080/login мы увидим страницу входа по умолчанию, предоставленную Auth0 :

./e2dc6b01aa4cb024920ef2f68b25a3aa.png

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

./fc85fa1ed2fa9cf7461f52b4da2fca4b.png

Кроме того, мы найдем кнопку «Зарегистрироваться» (рядом с «Войти») на экране входа по умолчанию для самостоятельной регистрации.

6. Регистрация

6.1. Самостоятельная регистрация

Впервые мы можем создать учетную запись Auth0, нажав кнопку «Зарегистрироваться», а затем предоставив информацию, такую как адрес электронной почты и пароль:

./8a0216eb0839bc745b6e4c80280c9f45.png

6.2. Создать пользователя

Или мы можем создать нового пользователя из меню « Пользователи » в учетной записи Auth0:

./5391a8afe7bb75ac65ff6e90747b9942.png

6.3. Настройки подключений

Кроме того, мы можем выбрать различные типы подключений, такие как база данных и вход через социальные сети для регистрации/входа в наше приложение Spring Boot:

./26754d78959c489ea2a3ca3516eb7791.png

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

./983d7a26c1d4443ccc68cd0c2c2ab1d0.png

7. Логаутконтроллер

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

Создадим класс LogoutController , реализующий класс LogoutSuccessHandler :

@Controller
public class LogoutController implements LogoutSuccessHandler {
@Autowired
private AuthConfig config;

@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse res,
Authentication authentication) {
if (req.getSession() != null) {
req.getSession().invalidate();
}
String returnTo = "http://localhost:8080/";
String logoutUrl = "https://dev-example.auth0.com/v2/logout?client_id=" +
config.getClientId() + "&returnTo=" +returnTo;
res.sendRedirect(logoutUrl);
}
}

Здесь метод onLogoutSuccess переопределяется для вызова URL-адреса выхода /v2/logout Auth0.

8. API управления Auth0

До сих пор мы видели интеграцию безопасности Auth0 в приложении Spring Boot. Теперь давайте взаимодействуем с API управления Auth0 (системный API) в том же приложении.

8.1. Создать новое приложение

Во-первых, чтобы получить доступ к API управления Auth0, мы создадим межмашинное приложение в учетной записи Auth0:

./391f0275ab7286640426d9799bdd2e6c.png

8.2. Авторизация

Затем мы добавим авторизацию в Auth0 Management API с разрешениями на чтение/создание пользователей:

./b3257a6ad65b50491bfbdc139f8591ba.png

8.3. Учетные данные клиента

Наконец, мы получим идентификатор клиента и секрет клиента для доступа к приложению управления Auth0 из нашего приложения Spring Boot:

./7da2d239a68073b170ce77c26845e8d1.png

8.4. Токен доступа

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

public String getManagementApiToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

JSONObject requestBody = new JSONObject();
requestBody.put("client_id", "auth0ManagementAppClientId");
requestBody.put("client_secret", "auth0ManagementAppClientSecret");
requestBody.put("audience", "https://dev-example.auth0.com/api/v2/");
requestBody.put("grant_type", "client_credentials");

HttpEntity<String> request = new HttpEntity<String>(requestBody.toString(), headers);

RestTemplate restTemplate = new RestTemplate();
HashMap<String, String> result = restTemplate
.postForObject("https://dev-example.auth0.com/oauth/token", request, HashMap.class);

return result.get("access_token");
}

Здесь мы сделали запрос REST к URL- адресу /oauth/token Auth0 Token, чтобы получить токены доступа и обновления.

Кроме того, мы можем хранить эти учетные данные клиента в файле application.properties и читать их с помощью класса AuthConfig .

8.5. UserController

После этого создадим класс UserController с методом users :

@Controller
public class UserController {
@GetMapping(value="/users")
@ResponseBody
public ResponseEntity<String> users(HttpServletRequest request, HttpServletResponse response) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + getManagementApiToken());

HttpEntity<String> entity = new HttpEntity<String>(headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate
.exchange("https://dev-example.auth0.com/api/v2/users", HttpMethod.GET, entity, String.class);
return result;
}
}

Метод users получает список всех пользователей, отправляя запрос GET к API /api/v2/users Auth0 с токеном доступа, созданным в предыдущем разделе.

Итак, давайте получим доступ к localhost:8080/users , чтобы получить ответ JSON, содержащий всех пользователей:

[{
"created_at": "2020-05-05T14:38:18.955Z",
"email": "ansh@bans.com",
"email_verified": true,
"identities": [
{
"user_id": "5eb17a5a1cc1ac0c1487c37f78758",
"provider": "auth0",
"connection": "Username-Password-Authentication",
"isSocial": false
}
],
"name": "ansh@bans.com",
"nickname": "ansh",
"logins_count": 64
// ...
}]

8.6. Создать пользователя

Точно так же мы можем создать пользователя, отправив запрос POST к /api/v2/users Auth0 API:

@GetMapping(value = "/createUser")
@ResponseBody
public ResponseEntity<String> createUser(HttpServletResponse response) {
JSONObject request = new JSONObject();
request.put("email", "norman.lewis@email.com");
request.put("given_name", "Norman");
request.put("family_name", "Lewis");
request.put("connection", "Username-Password-Authentication");
request.put("password", "Pa33w0rd");

// ...
ResponseEntity<String> result = restTemplate
.postForEntity("https://dev-example.auth0.com/api/v2/users", request.toString(), String.class);
return result;
}

Затем давайте получим доступ к localhost:8080/createUser и проверим данные нового пользователя:

{
"created_at": "2020-05-10T12:30:15.343Z",
"email": "norman.lewis@email.com",
"email_verified": false,
"family_name": "Lewis",
"given_name": "Norman",
"identities": [
{
"connection": "Username-Password-Authentication",
"user_id": "5eb7f3d76b69bc0c120a8901576",
"provider": "auth0",
"isSocial": false
}
],
"name": "norman.lewis@email.com",
"nickname": "norman.lewis",
// ...
}

Similarly, we can perform various operations like listing all connections, creating a connection, listing all clients, and creating a client using Auth0 APIs, depending on our permissions.

9. Conclusion

In this tutorial, we explored Spring Security with Auth0.

First, we set up the Auth0 account with essential configurations. Then, we created a Spring Boot App and configured the application.properties for Spring Security integration with Auth0.

Next, we looked into creating an API token for the Auth0 Management API. Last, we looked into features like fetching all users and creating a user.

As usual, all the code implementations are available over on GitHub .