
Введение
Единый вход (SSO) — это процесс аутентификации, который позволяет пользователям получать доступ к нескольким приложениям, используя единый набор учетных данных для входа. Это повышает безопасность и удобство работы пользователей, упрощая управление несколькими учетными записями в различных службах. Эта статья проведет вас через процесс создания многопользовательской корпоративной SSO-интеграции с использованием Spring Boot, которая может интегрироваться с любым поставщиком SSO, таким как Google, Outlook и другими, для разных клиентов. Мы предоставим подробные пояснения и примеры кода для лучшего понимания процесса.
Предпосылки
Прежде чем мы углубимся, убедитесь, что у вас установлено и настроено следующее:
- Комплект для разработки Java (JDK) 8 или более поздней версии
- Апач Мавен
- Текстовый редактор или интегрированная среда разработки (IDE) по вашему выбору.
- Базовое понимание Spring Boot, OAuth 2.0 и OpenID Connect (OIDC)
Начало работы с Spring Boot
- Создайте новый проект Spring Boot с помощью Spring Initializr. Выберите следующие зависимости:
- Веб: «Весенняя паутина»
- Безопасность: «Весенняя безопасность»
- Клиент OAuth 2.0: «Клиент Spring Boot OAuth2»
2. Загрузите и извлеките сгенерированный проект.
3. Откройте проект в предпочтительной среде IDE и убедитесь, что все зависимости правильно загружены.
Внедрение SSO-интеграции
Мы будем использовать OAuth 2.0 и OpenID Connect (OIDC) для интеграции с внешними поставщиками SSO. OIDC — это уровень идентификации, созданный поверх OAuth 2.0, который обеспечивает функции аутентификации и авторизации. Выполните следующие действия, чтобы реализовать интеграцию SSO с несколькими арендаторами.
- Обновите файл
application.properties:
# Base properties for SSO integration spring.security.oauth2.client.registration.dynamic.registration-id=<your_registration_id> spring.security.oauth2.client.registration.dynamic.scope=openid,email,profile # These properties will be dynamically overridden for each tenant spring.security.oauth2.client.registration.dynamic.client-id=<your_client_id> spring.security.oauth2.client.registration.dynamic.client-secret=<your_client_secret> spring.security.oauth2.client.registration.dynamic.provider=<your_sso_provider>
Замените <your_registration_id>, <your_client_id>, <your_client_secret> и <your_sso_provider> фактическими значениями, полученными от поставщика единого входа.
2. Создайте новый класс DynamicOAuth2ClientRegistration для хранения сведений о динамической регистрации клиента:
package com.example.sso;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
public class DynamicOAuth2ClientRegistration {
private String tenantId;
private ClientRegistration clientRegistration;
// Constructor, getters, and setters
}
3. Создайте новый класс DynamicOAuth2ClientRegistrationRepository, реализующий ClientRegistrationRepository:
package com.example.sso;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import java.util.HashMap;
import java.util.Map;
public class DynamicOAuth2ClientRegistrationRepository implements ClientRegistrationRepository {
private final Map<String, DynamicOAuth2ClientRegistration> dynamicClientRegistrations;
public DynamicOAuth2ClientRegistrationRepository() {
this.dynamicClientRegistrations = new HashMap<>();
}
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
// Retrieve the client registration for the given tenant
DynamicOAuth2ClientRegistration dynamicRegistration = dynamicClientRegistrations.get(registrationId);
return dynamicRegistration == null ? null : dynamicRegistration.getClientRegistration();
}
// Additional methods for managing dynamic client registrations
}
4. Измените класс WebSecurityConfig, чтобы настроить bean-компонент DynamicOAuth2ClientRegistrationRepository и внедрить его в конфигурацию HttpSecurity:
package com.example.sso;
// ...other imports...
import org.springframework.context.annotation.Bean;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public DynamicOAuth2ClientRegistrationRepository dynamicClientRegistrationRepository() {
return new DynamicOAuth2ClientRegistrationRepository();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// ...existing code...
.and()
.oauth2Login()
.clientRegistrationRepository(dynamicClientRegistrationRepository())
.defaultSuccessURL("/user", true);
}
}
5. Создайте новый класс Tenant для представления информации о каждом арендаторе:
package com.example.sso;
public class Tenant {
private String id;
private String name;
private String ssoProvider;
private String clientId;
private String clientSecret;
// Constructor, getters, and setters
}
6. Добавьте новый класс TenantRepository для хранения информации об арендаторах и управления ею:
package com.example.sso;
import java.util.List;
public interface TenantRepository {
Tenant findById(String id);
List<Tenant> findAll();
Tenant save(Tenant tenant);
void deleteById(String id);
}
Вы можете реализовать TenantRepository, используя предпочтительную технологию базы данных (например, JPA, JDBC, MongoDB и т. д.). В этой статье не рассматриваются конкретные детали реализации базы данных, но вы можете найти дополнительную информацию в Документации Spring Data.
7. Создайте новый класс TenantService для обработки логики конкретного арендатора:
package com.example.sso;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TenantService {
@Autowired
private TenantRepository tenantRepository;
public Tenant findById(String id) {
return tenantRepository.findById(id);
}
public List<Tenant> findAll() {
return tenantRepository.findAll();
}
public Tenant save(Tenant tenant) {
return tenantRepository.save(tenant);
}
public void deleteById(String id) {
tenantRepository.deleteById(id);
}
}
8. Обновите класс DynamicOAuth2ClientRegistrationRepository, чтобы внедрить TenantService и получить сведения о регистрации клиента для конкретного арендатора:
package com.example.sso;
// ...other imports...
import org.springframework.beans.factory.annotation.Autowired;
public class DynamicOAuth2ClientRegistrationRepository implements ClientRegistrationRepository {
// ...existing code...
@Autowired
private TenantService tenantService;
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
Tenant tenant = tenantService.findById(registrationId);
if (tenant == null) {
return null;
}
// Create a dynamic client registration based on the tenant's SSO provider
DynamicOAuth2ClientRegistration dynamicRegistration = createDynamicClientRegistration(tenant);
return dynamicRegistration == null ? null : dynamicRegistration.getClientRegistration();
}
// ...other methods...
private DynamicOAuth2ClientRegistration createDynamicClientRegistration(Tenant tenant) {
// Retrieve the OAuth2 provider details based on the tenant's SSO provider
// and create a dynamic client registration using the tenant's client ID and secret
}
}
9. Обновите класс WebSecurityConfig, чтобы настроить bean-компонент DynamicOAuth2ClientRegistrationRepository и внедрить его в конфигурацию HttpSecurity:
package com.example.sso;
// ...other imports...
import org.springframework.context.annotation.Bean;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public DynamicOAuth2ClientRegistrationRepository dynamicClientRegistrationRepository() {
return new DynamicOAuth2ClientRegistrationRepository();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// ...existing code...
.and()
.oauth2Login()
.clientRegistrationRepository(dynamicClientRegistrationRepository())
.defaultSuccessURL("/user", true);
}
}
Теперь ваше приложение готово к интеграции многопользовательской системы единого входа с различными поставщиками. Вы можете хранить поставщика единого входа для каждого арендатора, идентификатор клиента и секрет клиента в базе данных и динамически извлекать сведения о регистрации клиента на основе текущего арендатора.
Тестирование мультитенантной интеграции единого входа
Чтобы протестировать интеграцию SSO с несколькими арендаторами, вы можете создать простое веб-приложение со страницей входа, которая отображает доступных поставщиков SSO для каждого арендатора. Выполните следующие шаги:
- Обновите файл
application.properties, чтобы включить зависимость Thymeleaf:
spring.thymeleaf.cache=false
2. Добавьте зависимость Thymeleaf к вашему pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3. Создайте новый класс контроллера LoginController:
package com.example.sso;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Controller
public class LoginController {
@Autowired
private TenantService tenantService;
@GetMapping("/login/{tenantId}")
public String login(@PathVariable("tenantId") String tenantId, Model model) {
Tenant tenant = tenantService.findById(tenantId);
if (tenant == null) {
return "error";
}
model.addAttribute("tenant", tenant);
return "login";
}
}
4. Создайте новый шаблон Thymeleaf src/main/resources/templates/login.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<h1>Login with SSO Provider</h1>
<div th:if="${tenant.ssoProvider == 'google'}">
<a th:href="@{/oauth2/authorization/{tenantId}(tenantId=${tenant.id})}">Login with Google</a>
</div>
<div th:if="${tenant.ssoProvider == 'outlook'}">
<a th:href="@{/oauth2/authorization/{tenantId}(tenantId=${tenant.id})}">Login with Outlook</a>
</div>
<!-- Add other SSO providers as needed -->
</body>
</html>
Теперь вы можете запустить свое приложение и протестировать интеграцию SSO с несколькими арендаторами, посетив URL-адрес /login/{tenantId} с соответствующим идентификатором арендатора. После успешной аутентификации пользователь будет перенаправлен на URL-адрес /user.
Заключение
В этой статье мы продемонстрировали, как создать мультитенантную интеграцию SSO предприятия с Spring Boot, которая может интегрироваться с различными поставщиками SSO, такими как Google, Outlook, Okta и другими. Реализация использует OAuth 2.0 и OpenID Connect (OIDC) для обеспечения функций аутентификации и авторизации. Мы рассмотрели необходимую конфигурацию, дизайн базы данных.
🔗 Свяжитесь со мной в LinkedIn!
Я надеюсь, что вы нашли эту статью полезной! Если вы хотите узнать больше и быть в курсе моих последних идей и статей, не стесняйтесь связаться со мной в LinkedIn.
Давайте расширять наши сети, участвовать в содержательных дискуссиях и делиться своим опытом в мире разработки программного обеспечения и за его пределами. С нетерпением ждем связи с вами! 😊