Spring Security - @PreFilter e @PostFilter
1. Visão geral
Neste artigo, aprenderemos como usar as anotações@PreFiltere@PostFilter para proteger as operações em um aplicativo Spring.
Quando usado junto com as informações principais autenticadas,@PreFiltere@PostFilter nos permite definir regras de segurança refinadas usando Spring Expression Language.
2. Apresentando@PreFilter e@PostFilter
Simplificando, as anotações@PreFiltere@PostFilter sãoused to filter lists of objects com base nas regras de segurança personalizadas que definimos.
@PostFilter define uma regra para filtrar a lista de retorno de um método, porapplying that rule to every element in the list. Se o valor avaliado for verdadeiro, o item será mantido na lista. Caso contrário, o item será removido.
@PreFilter funciona de maneira muito semelhante, no entanto, a filtragem é aplicada a uma lista que está sendo passada como um parâmetro de entrada para o método anotado.
Ambas as anotações podem ser usadas em métodos ou tipos (classes e interfaces). Vamos usá-los apenas em métodos ao longo deste artigo.
Essas anotações não estão ativas por padrão - precisaremos habilitá-las com a anotação@EnableGlobalMethodSecurity eprePostEnabled = true - em nossa configuração de segurança:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}
3. Escrevendo regras de segurança
Para escrever as regras de segurança nessas duas anotações - faremos uso de expressões Spring-EL; também podemos usar o objeto embutidofilterObject para obter uma referência ao elemento particular da lista que está sendo testado.
Spring Security fornecemany other built-in objects para criar regras muito específicas e exatas.
For example, podemos usar@PreFilter para verificar se a propriedadeassignee de um objetoTask é igual aname do usuário autenticado atualmente:
@PostFilter("filterObject.assignee == authentication.name")
List findAll() {
...
}
Usamos a anotação@PostFilter aqui, pois queremos que o método execute e obtenha todas as tarefas primeiro, e eles passam cada tarefa da lista por meio de nossa regra de filtro.
Portanto, se o usuário autenticado formichael, a lista final de tarefas retornada pelo métodofindAll conteria apenas as tarefas atribuídas amichael, mesmo se o banco de dados tiver tarefas atribuídas a jim epam.
Agora vamos tornar a regra um pouco mais interessante. Suponha que, se um usuário for um gerente, ele possa ver todas as tarefas, independentemente de a quem está atribuído:
@PostFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
List findAll() {
// ...
}
Usamos o método integradohasRole para verificar se o usuário autenticado tem a função de MANAGER. SehasRole retornar verdadeiro, a tarefa será mantida na lista final. Portanto, se o usuário for um gerente, a regra retornará verdadeiro para todos os itens da lista. Assim, a lista final conterá todos os itens.
Agora vamos filtrar uma lista passada como parâmetro para um métodosave usando@PreFilter:
@PreFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
Iterable save(Iterable entities) {
// ...
}
A regra de segurança é a mesma que usamos no exemplo@PostFilter. A principal diferença aqui é que os itens da lista serão filtrados antes da execução do método, permitindo remover alguns itens da lista, impedindo que sejam salvos no banco de dados.
Portanto,jim, que não é gerente, pode tentar salvar uma lista de tarefas, algumas das quais atribuídas apam. No entanto, apenas as tarefas atribuídas ajim serão incluídas, as outras serão ignoradas.
4. Desempenho em listas grandes
@PreFilter é muito legal e fácil de usar, mas pode ser ineficiente ao lidar com listas muito grandes, pois a operação de busca irá recuperar todos os dados e aplicar o filtro posteriormente.
Imagine, por exemplo, que temos milhares de tarefas em nosso banco de dados e queremos recuperar as cinco tarefas que estão atualmente atribuídas apam. Se usarmos@PreFilter,, a operação do banco de dados irá buscar todas as tarefas primeiro e iterar por todas elas para filtrar aquelas que não estão atribuídas apam.
5. Conclusão
Este artigo rápido explicou como criar um aplicativo simples, mas seguro, usando as anotações@PreFilter e@PostFilter do Spring Security.
Verifique o exemplo de código completoin this Github repository.