1. Обзор
В этом уроке мы обсудим, как реализовать SSO – Single Sign On – с помощью Spring Security OAuth и Spring Boot.
Мы будем использовать три отдельных приложения:
- Сервер авторизации – это центральный механизм аутентификации
- Два клиентских приложения: приложения, использующие SSO
Проще говоря, когда пользователь пытается получить доступ к защищенной странице в клиентском приложении, он сначала перенаправляется на аутентификацию через сервер аутентификации.
И мы собираемся использовать тип Authorization Code grant из OAuth2 для управления делегированием аутентификации.
Примечание : в этой статье используется Spring OAuth legacy project . Для версии этой статьи, использующей новый стек Spring Security 5, ознакомьтесь с нашей статьей Simple Single Sign-On with Spring Security OAuth2 .
2. Клиентское Приложение
Давайте начнем с нашего клиентского приложения; мы, конечно же, будем использовать Spring Boot, чтобы минимизировать конфигурацию:
2.1. Зависимости Maven
Во-первых, нам понадобятся следующие зависимости в вашем pom.xml :
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure 2.0.1.RELEASE org.springframework.boot spring-boot-starter-thymeleaf org.thymeleaf.extras thymeleaf-extras-springsecurity4
2.2. Конфигурация безопасности
Далее, самая важная часть, конфигурация безопасности нашего клиентского приложения:
@Configuration @EnableOAuth2Sso public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/", "/login**") .permitAll() .anyRequest() .authenticated(); } }
Основной частью этой конфигурации является, конечно же, аннотация @EnableOAuth2Sso , которую мы используем для включения единого входа.
Обратите внимание, что нам нужно расширить WebSecurityConfigurerAdapter – без него все пути будут защищены – так что пользователи будут перенаправлены на вход, когда они попытаются получить доступ к любой странице. В нашем случае страницы индекса и входа в систему-это единственные страницы, к которым можно получить доступ без аутентификации.
Наконец, мы также определили компонент RequestContextListener bean для обработки областей запросов.
И application.yml :
server: port: 8082 servlet: context-path: /ui session: cookie: name: UISESSION security: basic: enabled: false oauth2: client: clientId: SampleClientId clientSecret: secret accessTokenUri: http://localhost:8081/auth/oauth/token userAuthorizationUri: http://localhost:8081/auth/oauth/authorize resource: userInfoUri: http://localhost:8081/auth/user/me spring: thymeleaf: cache: false
Несколько быстрых заметок:
- мы отключили базовую аутентификацию по умолчанию
- accessTokenUri – это URI для получения токенов доступа
- userAuthorizationUri – это URI авторизации, на который будут перенаправлены пользователи
- userInfo Uri URI конечной точки пользователя для получения текущих сведений о пользователе
Также обратите внимание, что в нашем примере мы развернули наш сервер авторизации, но, конечно, мы также можем использовать других сторонних поставщиков, таких как Facebook или GitHub.
2.3. Передний конец
Теперь давайте взглянем на интерфейсную конфигурацию нашего клиентского приложения. Мы не будем заострять на этом внимание здесь, главным образом потому, что мы уже рассмотрели это на сайте .
Наше клиентское приложение здесь имеет очень простой интерфейс; вот index.html :
Spring Security SSO
Login
А то securedPage.html :
Secured Page
Welcome, Name
В securedPage.html страница нуждалась в аутентификации пользователей. Если пользователь, не прошедший проверку подлинности, пытается получить доступ к securedPage.html , сначала они будут перенаправлены на страницу входа в систему.
3. Сервер Аутентификации
Теперь давайте обсудим наш Сервер авторизации здесь.
3.1. Зависимости Maven
Во-первых, нам нужно определить зависимости в вашем pom.xml :
org.springframework.boot spring-boot-starter-web org.springframework.security.oauth spring-security-oauth2 2.3.3.RELEASE
3.2. Конфигурация OAuth
Важно понимать, что здесь мы будем запускать Сервер авторизации и Сервер ресурсов вместе, как единое развертываемое устройство.
Давайте начнем с конфигурации нашего Сервера ресурсов, который одновременно является нашим основным загрузочным приложением:
@SpringBootApplication @EnableResourceServer public class AuthorizationServerApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(AuthorizationServerApplication.class, args); } }
Затем мы настроим наш сервер авторизации:
@Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public void configure( AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("SampleClientId") .secret(passwordEncoder.encode("secret")) .authorizedGrantTypes("authorization_code") .scopes("user_info") .autoApprove(true) .redirectUris( "http://localhost:8082/ui/login","http://localhost:8083/ui2/login"); } }
Обратите внимание, что мы включаем только простой клиент, используя тип authorization_code grant.
Кроме того, обратите внимание, что auto Approve имеет значение true, чтобы мы не перенаправлялись и не продвигались для ручного утверждения каких-либо областей.
3.3. Конфигурация безопасности
Во-первых, мы отключим базовую аутентификацию по умолчанию с помощью нашего application.properties :
server.port=8081 server.servlet.context-path=/auth
Теперь давайте перейдем к конфигурации и определим простой механизм входа в форму:
@Configuration @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers() .antMatchers("/login", "/oauth/authorize") .and() .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("john") .password(passwordEncoder().encode("123")) .roles("USER"); } @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
Обратите внимание, что мы использовали простую аутентификацию в памяти, но мы можем просто заменить ее пользовательским UserDetailsService .
3.4. Конечная точка пользователя
Наконец, мы создадим нашу пользовательскую конечную точку, которую мы использовали ранее в нашей конфигурации:
@RestController public class UserController { @GetMapping("/user/me") public Principal user(Principal principal) { return principal; } }
Естественно, это вернет пользовательские данные с представлением JSON.
4. Заключение
В этом кратком руководстве мы сосредоточились на реализации единого входа с использованием Spring Security Oauth2 и Spring Boot.
Как всегда, полный исходный код можно найти на GitHub .