Logon único simples com Spring Security OAuth2

Logon único simples com Spring Security OAuth2

1. Visão geral

Neste tutorial, discutiremos como implementar SSO - Single Sign On - usando Spring Security OAuth e Spring Boot.

Usaremos três aplicativos separados:

  • Um servidor de autorização - que é o mecanismo de autenticação central

  • Dois aplicativos clientes: os aplicativos usando SSO

Simplificando, quando um usuário tenta acessar uma página segura no aplicativo cliente, ele será redirecionado para autenticar primeiro, por meio do servidor de autenticação.

E vamos usar o tipo de concessãoAuthorization Code fora do OAuth2 para conduzir a delegação de autenticação.

Leitura adicional:

Spring Security 5 - Login do OAuth2

Aprenda como autenticar usuários com o Facebook, Google ou outras credenciais usando o OAuth2 no Spring Security 5.

Read more

Novo no Spring Security OAuth2 - Verificar reivindicações

Introdução prática rápida ao novo suporte de verificação de Reivindicações no Spring Security OAuth.

Read more

Um login secundário no Facebook com o Spring Social

Uma rápida olhada na implementação de uma autenticação orientada pelo Facebook ao lado de um aplicativo Spring de login de formulário padrão.

Read more

 

Antes de começarmos - uma observação importante. Lembre-se de quethe Spring Security core team is in the process of implementing a new OAuth2 stack - com alguns aspectos já destacados e outros ainda em andamento.

Aqui está um vídeo rápido que lhe dará algum contexto sobre esse esforço:

 

Tudo bem, vamos começar.

2. O aplicativo cliente

Vamos começar com nosso aplicativo de cliente; vamos, é claro, usar Spring Boot para minimizar a configuração:

2.1. Dependências do Maven

Primeiro, precisaremos das seguintes dependências em nossopom.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. Configuração de segurança

A seguir, a parte mais importante, a configuração de segurança do nosso aplicativo cliente:

@Configuration
@EnableOAuth2Sso
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
          .authorizeRequests()
          .antMatchers("/", "/login**")
          .permitAll()
          .anyRequest()
          .authenticated();
    }
}

A parte central desta configuração é, obviamente, a anotação@EnableOAuth2Sso que estamos usando para habilitar o Single Sign On.

Observe que precisamos estender oWebSecurityConfigurerAdapter - sem ele, todos os caminhos serão protegidos - para que os usuários sejam redirecionados para fazer login quando tentarem acessar qualquer página. No nosso caso aqui, as páginas de índice e login são as únicas páginas que podem ser acessadas sem autenticação.

Finalmente, também definimos um beanRequestContextListener para lidar com escopos de solicitações.

E oapplication.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

Algumas notas rápidas:

  • desativamos a autenticação básica padrão

  • accessTokenUri é o URI para obter os tokens de acesso

  • userAuthorizationUri é o URI de autorização para o qual os usuários serão redirecionados

  • userInfoUri o URI do endpoint do usuário para obter os detalhes atuais do usuário

Observe também que, em nosso exemplo aqui, lançamos nosso Servidor de Autorização, mas é claro que também podemos usar outros fornecedores de terceiros, como o Facebook ou o GitHub.

2.3. a parte dianteira

Agora, vamos dar uma olhada na configuração de front-end de nosso aplicativo cliente. Não vamos focar nisso aqui, principalmente porque nósalready covered in on the site.

Nosso aplicativo cliente aqui tem um front-end muito simples; aqui está oindex.html:

Spring Security SSO

Login

E osecuredPage.html:

Secured Page

Welcome, Name

A páginasecuredPage.html precisava que os usuários fossem autenticados. Se um usuário não autenticado tentar acessarsecuredPage.html, ele será redirecionado para a página de login primeiro.

3. O Servidor Auth

Agora vamos discutir nosso servidor de autorização aqui.

3.1. Dependências do Maven

Primeiro, precisamos definir as dependências em nossopom.xml:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.security.oauth
    spring-security-oauth2
    2.3.3.RELEASE

3.2. Configuração OAuth

É importante entender que vamos executar o Authorization Server e o Resource Server juntos aqui, como uma única unidade implantável.

Vamos começar com a configuração do nosso servidor de recursos - que funciona como nosso aplicativo de inicialização principal:

@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(AuthorizationServerApplication.class, args);
    }
}

Então, vamos configurar nosso servidor de autorização:

@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");
    }
}

Observe como estamos habilitando apenas um cliente simples usando o tipo de concessãoauthorization_code.

Além disso, observe comoautoApprove é definido como verdadeiro para que não sejamos redirecionados e promovidos a aprovar manualmente quaisquer escopos.

3.3. Configuração de segurança

Primeiro, vamos desativar a autenticação básica padrão, por meio de nossoapplication.properties:

server.port=8081
server.servlet.context-path=/auth

Agora, vamos passar para a configuração e definir um mecanismo de login de formulário simples:

@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();
    }
}

Observe que usamos autenticação simples na memória, mas podemos simplesmente substituí-la por umuserDetailsService personalizado.

3.4. Endpoint do usuário

Por fim, criaremos nosso terminal de usuário que usamos anteriormente em nossa configuração:

@RestController
public class UserController {
    @GetMapping("/user/me")
    public Principal user(Principal principal) {
        return principal;
    }
}

Naturalmente, isso retornará os dados do usuário com uma representação JSON.

4. Conclusão

Neste tutorial rápido, focamos na implementação do Logon único usando o Spring Security Oauth2 e o Spring Boot.

Como sempre, o código-fonte completo pode ser encontradoover on GitHub.