«1. Обзор
Auth0 предоставляет службы аутентификации и авторизации для различных типов приложений, таких как собственные приложения, одностраничные приложения и веб-приложения. Кроме того, он позволяет реализовать различные функции, такие как единый вход, вход через социальные сети и многофакторную аутентификацию.
В этом руководстве мы рассмотрим Spring Security с Auth0 с помощью пошагового руководства, а также основные настройки учетной записи Auth0.
2. Настройка Auth0
2.1. Регистрация Auth0
Во-первых, мы подпишемся на бесплатный план Auth0, который обеспечивает доступ до 7 тысяч активных пользователей с неограниченным количеством входов в систему. Однако мы можем пропустить этот раздел, если он у нас уже есть:
2.2. Панель инструментов
После входа в учетную запись Auth0 мы увидим панель инструментов, на которой отображаются такие сведения, как действия при входе в систему, последние входы в систему и новые регистрации:
2.3. Создайте новое приложение
Затем в меню «Приложения» мы создадим новое приложение OpenID Connect (OIDC) для Spring Boot.
Далее мы выберем обычные веб-приложения в качестве типа приложения из доступных вариантов, таких как собственные, одностраничные приложения и межмашинные приложения:
2.4. Настройки приложения
Далее мы настроим несколько URI приложений, таких как URL-адреса обратного вызова и URL-адреса выхода, указывающие на наше приложение:
2.5. Учетные данные клиента
Наконец, мы получим значения домена, идентификатора клиента и секрета клиента, связанные с нашим приложением:
Держите эти учетные данные под рукой, поскольку они необходимы для настройки Auth0 в нашем приложении Spring Boot.
3. Настройка приложения Spring Boot
Теперь, когда наша учетная запись Auth0 готова с ключевыми конфигурациями, мы готовы интегрировать безопасность Auth0 в приложение Spring Boot.
3.1. Maven
Во-первых, давайте добавим последнюю зависимость mvc-auth-commons Maven в наш pom.xml:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>1.2.0</version>
</dependency>
3.2. Gradle
Аналогично, при использовании Gradle мы можем добавить зависимость mvc-auth-commons в файл build.gradle:
compile 'com.auth0:mvc-auth-commons:1.2.0'
3.3. application.properties
Нашему приложению Spring Boot требуется такая информация, как идентификатор клиента и секрет клиента, чтобы включить аутентификацию учетной записи Auth0. Итак, добавим их в файл application.properties:
com.auth0.domain: dev-example.auth0.com
com.auth0.clientId: {clientId}
com.auth0.clientSecret: {clientSecret}
3.4. AuthConfig
Далее мы создадим класс 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
Наконец, мы добавим ссылку на bean-компонент для класса 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
Далее мы создадим класс 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:
После входа в систему с использованием зарегистрированного пользователя учетные данные, будет показано приветственное сообщение с адресом электронной почты пользователя:
Кроме того, мы найдем кнопку «Зарегистрироваться» (рядом с «Войти») на экране входа по умолчанию для самостоятельной регистрации. .
6. Регистрация
6.1. Самостоятельная регистрация
Впервые мы можем создать учетную запись Auth0, используя кнопку «Зарегистрироваться», а затем предоставив информацию, такую как адрес электронной почты и пароль:
6.2. Создать пользователя
Или мы можем создать нового пользователя из меню «Пользователи» в учетной записи Auth0:
6.3. Настройки подключений
Кроме того, мы можем выбрать различные типы подключений, такие как база данных и вход в социальные сети для регистрации/входа в наше приложение Spring Boot:
Кроме того, на выбор доступен ряд социальных подключений: ~ ~~ 7. LogoutController
Теперь, когда мы увидели функции входа и обратного вызова, мы можем добавить функцию выхода из системы в наше приложение Spring Boot.
Давайте создадим класс LogoutController, реализующий класс LogoutSuccessHandler:
Здесь метод onLogoutSuccess переопределен для вызова URL-адреса выхода /v2/logout Auth0.
@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);
}
}
8. API управления Auth0
До сих пор мы видели интеграцию безопасности Auth0 в приложении Spring Boot. Теперь давайте взаимодействуем с API управления Auth0 (системный API) в том же приложении.
8.1. Создание нового приложения
Во-первых, чтобы получить доступ к API управления Auth0, мы создадим межмашинное приложение в учетной записи Auth0:
8.2. Авторизация
Затем мы добавим авторизацию в Auth0 Management API с разрешениями на чтение/создание пользователей:
8.3. Учетные данные клиента
Наконец, мы получим идентификатор клиента и секрет клиента для доступа к приложению управления Auth0 из нашего приложения Spring Boot:
8.4. Токен доступа
Давайте создадим токен доступа для приложения управления Auth0, используя учетные данные клиента, полученные в предыдущем разделе:
Здесь мы сделали запрос REST к URL токена /oauth/token 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");
}
Кроме того, мы можем хранить эти учетные данные клиента в файле application.properties и читать их с помощью класса AuthConfig.
8.5. UserController
После этого давайте создадим класс UserController с методом пользователей:
Метод пользователей получает список всех пользователей, выполняя запрос GET к /api/v2/users Auth0 API с доступом токен, созданный в предыдущем разделе.
@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;
}
}
Итак, давайте получим доступ к localhost:8080/users, чтобы получить ответ JSON, содержащий всех пользователей:
8.6. Создать пользователя
[{
"created_at": "2020-05-05T14:38:18.955Z",
"email": "[email protected]",
"email_verified": true,
"identities": [
{
"user_id": "5eb17a5a1cc1ac0c1487c37f78758",
"provider": "auth0",
"connection": "Username-Password-Authentication",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "ansh",
"logins_count": 64
// ...
}]
Точно так же мы можем создать пользователя, отправив запрос POST к /api/v2/users Auth0 API:
Затем давайте получим доступ к localhost:8080/createUser и проверим данные нового пользователя:
@GetMapping(value = "/createUser")
@ResponseBody
public ResponseEntity<String> createUser(HttpServletResponse response) {
JSONObject request = new JSONObject();
request.put("email", "[email protected]");
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;
}
Точно так же мы можем выполнять различные операции, такие как вывод списка всех подключений, создание подключения, вывод списка всех клиентов и создание клиента с использованием API-интерфейсов Auth0, в зависимости от наших разрешений.
{
"created_at": "2020-05-10T12:30:15.343Z",
"email": "[email protected]",
"email_verified": false,
"family_name": "Lewis",
"given_name": "Norman",
"identities": [
{
"connection": "Username-Password-Authentication",
"user_id": "5eb7f3d76b69bc0c120a8901576",
"provider": "auth0",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "norman.lewis",
// ...
}
9. Заключение
В этом руководстве мы изучили Spring Security с Auth0.
Сначала мы настраиваем учетную запись Auth0 с необходимыми настройками. Затем мы создали приложение Spring Boot и настроили application.properties для интеграции Spring Security с Auth0.
Далее мы рассмотрели создание токена API для API управления Auth0. Наконец, мы рассмотрели такие функции, как получение всех пользователей и создание пользователя.
Как обычно, все реализации кода доступны на GitHub.
«