Autenticação Basic com Java Spring
Published: 2021-03-11 11:59:01

A autenticação de usuários é uma necessidade básica em boa parte das aplicações *web* e *mobile*. Realizar essa autenticação utilizando o *framework* Spring é fácil. Este artigo mostra como realizar a autenticação básica no Spring, com a criação de um servidor de recursos (*Resource Server*) e a configuração com o modelo Basic.

## Introdução
A autenticação *Basic* é a forma mais simples de autenticar um usuário. Ela consiste na configuração de um servidor de recursos e a  definição de um usuário e senha. O Spring possui essa autenticação embutida automaticamente no pacote `spring-boot-starter-security`, ou seja, caso essa dependência seja adicionada ao projeto já é possível utilizar essa autenticação sem a necessidade de configurações adicionais. 
No entanto, para definir usuários e senhas específicos para a aplicação é necessário que algumas configurações sejam adicionadas ao projeto. 

## Criação do projeto base

O projeto base pode ser criado utilizando qualquer ferramenta/IDE que permita a geração de projetos Spring. Algumas opções para realizar esta tarefa são:
* [Spring Initializr](https://start.spring.io/)
* [IDE Spring Tool Suite (STS)](https://spring.io/tools)
* Visual Studio Code com extensão [Spring Tool](https://marketplace.visualstudio.com/items?itemName=Pivotal.vscode-boot-dev-pack)

Na criação do projeto devem ser adicionadas as dependências 
* Spring Boot Starter Web
* Spring Security

Para os testes da autenticação de rotas é necessário implementar um controlador simples. Este controlador proverá conteúdos estáticos, apenas para exemplificar o funcionamento.

```java
@RestController
@RequestMapping("/main")
public class BasicController {

    @GetMapping("protect")
    public String protectedRoute() {
        return "Rota Protegida";
    }

    @GetMapping("free")
    public String unprotectedRoute() {
        return "Rota Livre";
    }
}
```

A princípio, as duas rotas estarão bloqueadas para acesso autenticado apenas. Após a configuração personalizada será possível liberar uma delas da autenticação e deixar a outra protegida. 

Com essas duas dependências adicionadas uma configuração de segurança padrão é adicionada ao projeto utilizando o nome de usuário `user` e uma senha aleatória que é mostrada no log de inicialização do sistema, conforme mostrado na figura a seguir

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yfb8f9dmm8trfb8i4l9l.png)
 
Além disso, o Spring provê automaticamente a seguinte página de *login*
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nkft4sswamafdv2ttrkn.png)
> A estilização desta página de login e sua correta configuração não estão no escopo deste artigo

O maior problema desta geração de senha padrão é que a cada reinicialização do sistema a senha será alterada, tornando essa configuração padrão inviável para ambiente de produção e muito difícil de gerenciar até em ambiente de desenvolvimento.

## Configurando o usuário e senha através das propriedades

Algumas propriedades de configuração da aplicação podem ser definidas no arquivo `application.properties` ou no arquivo `application.yml`, assim como via linha de comando. Dentre estas propriedades estão o usuário e senha para a autenticação Basic. Um exemplo de configuração é mostrado a seguir, com a alteração do nome do usuário para `alexandre` e a senha para `123456` 

```
spring.security.user.name=alexandre
spring.security.user.password=123456
``` 

A figura a seguir é um print da tela do Insomnia, uma ferramenta gratuita para teste de APIs, quando é feita a requisição para a rota `/main/protect` sem que sejam passadas as informações de usuário e senha. O retorno é um status HTTP 403, que informa que o usuário não está autorizado a acessar o recurso. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/244au9n7eum08zjzsur1.png)

O mesmo resultado é obtido para a rota `/main/free` sem autenticação
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zqlymx8dbumrkom4hgow.png)

Para obter um resultado de sucesso na requisição é necessário configurar a autenticação, conforme mostrado a seguir.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ym3xahkbc8vknnbql5xt.png)

Esta configuração  pode ser interessante para ambientes de desenvolvimento, mas dificilmente será utilizada em produção, a não ser em casos específicos em que apenas um usuário é necessário.

## Personalizando configurações da autenticação Basic
 
Para personalizar alguns aspectos da autenticação Basic é preciso criar uma nova classe para redefinir as configurações do Spring Security. Esta classe sobrescreverá as configurações realizadas pela classe `WebSecurityConfigurerAdapter` e seu código inicial é o seguinte

```java
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

}
```

> Conforme já mencionado, esta é uma classe de configuração para o Spring. Sendo assim, ela poderia ser explicitamente anotada com `@Configuration`. No entanto, como a anotação `@EnableWebSecurity` já traz consigo a anotação `@Configuration` não é necessária a repetição da mesma. Entretanto, não é errado fazer isso e o código fica mais legível.

### Métodos de configuração
A classe `WebSecurityConfigurerAdapter` possui alguns métodos de configuração com a assinatura `configure`. Estes métodos podem ser sobrescritos para a personalização da autenticação com relação às requisições HTTP e também dos usuário permitidos.

### Método `configure(HttpSecurity http)`
Este método permite a alteração de configurações relativas às requisições do protocolo HTTP, tais como o fluxo de autenticação, o formulário de login padrão (já citado anteriormente), as requisições que serão protegidas pela autenticação, o tipo de *token* que será utilizado (quando necessário), configuração de servidores *stateless* ou *stateless*, dentre outras configurações. A [documentação oficial](https://docs.spring.io/spring-security/site/docs/4.0.3.RELEASE/apidocs/org/springframework/security/config/annotation/web/builders/HttpSecurity.html) do Spring traz uma relação das configurações possíveis de serem realizadas neste método de configuração.
Para este projeto serão utilizadas as seguintes configurações  
* Definição do HTTP Basic como método de autenticação
* Desabilitação do *form login*
* Definição de rotas que deverão ser autenticadas ou não
* Configuração de gerenciamento de sessão

Os dois primeiros itens da lista são configurados da seguinte forma

```java
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic();
}
```

O *form login* é habilitado através do método `formLogin()`. A omissão deste método na configuração é suficiente para a sua inativação. Para concatenar configurações pode ser utilizado o método `and()`. Sendo assim, a habilitação do *login* pode ser feita com a configuração `http.httpBasic().and.formLogin()`.

A definição de quais rotas deverão ser autenticadas ou não é feita pelo método `authorizeRequests()`. Este método permite a configuração através dos métodos `antMatchers` e `anyRequest`, sendo o primeiro para definir de forma personalizada a rota e o segundo uma forma generalista para buscar todas as outras requisições. Neste exemplo será configurada a permissão para acessar a rota `/main/free` sem autenticação e todas as outras rotas precisarão passar por autenticação prévia. 

```java
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic().and()      
      .authorizeRequests()
          .antMatchers("/main/free").permitAll()
          .anyRequest().authenticated();
}
```

Outra configuração importante é referente ao controle de sessão e armazenamento de *cookies*. Por padrão, o Spring Security armazena *cookies* que retém informações sobre a autenticação previamente realizada. Isso permite que após uma requisição bem sucedida com autenticação o usuário consiga acessar o recurso mesmo que não utilize os dados de autenticação. Esse é um problema que deve ser resolvido e uma das formas de fazer isso é configurando o gerenciamento de sessão para que seja utilizada uma política *stateless*, ou seja, sem armazenamento de estado. Para isso, pode ser adicionado à configuração anterior o método `sessionManagement`, da seguinte forma.


```java
@Override
protected void configure(HttpSecurity http) throws Exception {
  http.httpBasic()
    .and()      
      .authorizeRequests()
        .antMatchers("/main/free").permitAll()
        .anyRequest().authenticated()
    .and()
      .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
```

### Método `configure(AuthenticationManagerBuilder auth)`

Este método permite a configuração de usuários e senhas para a aplicação. Neste artigo é abordada apenas uma estratégia de armazenamento destes usuários em memória de forma completamente programática (definidos no próprio código). 

Para configurar a autenticação em memória é utilizado o método `inMemoryAuthentication()` que permite as seguintes configurações
* Nome do usuário: `withUser("nome")`
* Senha: `password("password")`
* Permissões: `roles("roles")`

A partir da versão 5 do *Spring Security* é necessário colocar qualquer tipo de senha de forma codificada para o correto funcionamento. Uma forma de fazer isso é colocar a configuração do *password* como `password("{noop}password")`, o que delega ao `NoOpPasswrodEncoder` a responsabilidade de realizar a codificação. Essa opção deve ser utilizada com muito cuidado, pois expõe um dado sensível no código, e não deve ser utilizada em ambiente de produção.

A configuração completa do método fica da seguinte forma

```java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("alexandre")
        .password("{noop}123456")
        .roles("roles");
}
```
É possível colocar outros usuários nesta configuração utilizando o conectivo `and()`.
```java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("alexandre")
            .password("{noop}123456")
            .roles("roles")
        .and()
            .withUser("admin")
            .password("{noop}admin")
            .roles("roles");
}
```

##Conclusão
Este artigo mostrou a configuração inicial de autenticação *Basic* utilizando o *Spring Security*. Foram abordadas as questões sobre os métodos necessários para uma personalização simples da autenticação como configuração de usuários e senhas e definição de rotas que devem ou não ser autenticadas. 
Apesar de haver uma configuração obrigatória de definição de permissões na configuração de usuários, a mesma não foi utilizada para definição de autorizações nas rotas. Esse tema poderá ser explicado em um futuro trabalho.