Простой единый вход в Spring Security OAuth2

Простой единый вход в Spring Security OAuth2

1. обзор

В этом руководстве мы обсудим, как реализовать SSO - Single Sign On - с помощью Spring Security OAuth и Spring Boot.

Мы будем использовать три отдельных приложения:

  • Сервер авторизации - это центральный механизм аутентификации

  • Два клиентских приложения: приложения, использующие единый вход

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

И мы собираемся использовать тип предоставленияAuthorization Code из OAuth2, чтобы управлять делегированием аутентификации.

Дальнейшее чтение:

Spring Security 5 - OAuth2 Войти

Узнайте, как аутентифицировать пользователей с помощью Facebook, Google или других учетных данных с помощью OAuth2 в Spring Security 5.

Read more

Новое в Spring Security OAuth2 - Проверка заявок

Краткое практическое введение в новую поддержку проверки претензий в Spring Security OAuth.

Read more

Вторичный вход в Facebook через Spring Social

Краткий обзор реализации аутентификации на основе Facebook рядом со стандартным приложением Spring для входа в форму.

Read more

 

Прежде чем мы начнем - одно важное замечание. Имейте в виду, чтоthe Spring Security core team is in the process of implementing a new OAuth2 stack - некоторые аспекты уже выполнены, а некоторые все еще находятся в процессе разработки.

Вот короткое видео, которое даст вам некоторый контекст вокруг этих усилий:

 

Хорошо, приступим.

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 - без него все пути будут защищены - поэтому пользователи будут перенаправлены для входа в систему, когда они попытаются получить доступ к любой странице. В нашем случае страницы индекса и логина являются единственными страницами, к которым можно получить доступ без аутентификации.

Наконец, мы также определили bean-компонентRequestContextListener для обработки областей запросов.

И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 авторизации, на который будут перенаправлены пользователи.

  • userInfoUri URI конечной точки пользователя для получения сведений о текущем пользователе

Также обратите внимание, что в нашем примере мы развернули наш Сервер авторизации, но, конечно, мы также можем использовать других сторонних поставщиков, таких как Facebook или GitHub.

2.3. Внешний интерфейс

Теперь давайте посмотрим на конфигурацию внешнего интерфейса нашего клиентского приложения. Мы не собираемся здесь заострять внимание на этом, в основном потому, что мыalready covered in on the site.

У нашего клиентского приложения очень простой интерфейс; вот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.

Также обратите внимание, что дляautoApprove задано значение 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.

Как всегда, полный исходный код можно найтиover on GitHub.