Solucionado (ver solução)
Solucionado
(ver solução)
7
respostas

Erro no SecurityFilterChain do Spring Boot - Versão 3.1,2

Estou tentando iniciar a aplicação e ocorre o seguinte erro:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Unsatisfied dependency expressed through method 'setFilterChains' parameter 0: Error creating bean with name 'securityFilterChain' defined in class path resource [med/vol/api/config/SecurityConfig.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'securityFilterChain' threw exception with message: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Código da Classe SecurityConfig:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private SecurityFilter securityFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf(csrf -> csrf.disable())
                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(req -> {
                    req.requestMatchers(HttpMethod.POST, "/login").permitAll();
                    req.anyRequest().authenticated();
                })
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

Código da Classe SecurityFilter

@Component
public class SecurityFilter extends OncePerRequestFilter {

    @Autowired
    private ManagerTokenService tokenService;

    @Autowired
    private UsuarioRepository repository;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        var tokenJWT = recuperarToken(request);

        if(tokenJWT != null) {
            var validateToken = tokenService.getSubject(tokenJWT);
            var usuario = repository.findByLogin(validateToken);
            var autenticacao = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(autenticacao);
        }

        filterChain.doFilter(request,response);
    }

    private String recuperarToken(HttpServletRequest request) {

        var authorizationHeader = request.getHeader("Authorization");

        if(authorizationHeader != null) {
            return authorizationHeader.replace("Bearer","");
        }

        return null;
    }
}
7 respostas

Oi!

Teve uma mudança no Spring Security, mas não deveria acontecer no projeto do curso. A não ser que você não esteja utilizando o MySQL e sim o banco de dados H2 e tenha habilitado o console do h2 no application.properties.

Realmente, havia ocorrido um erro e eu acabei colocando uma dependência do H2, naquele momento resolveu o erro. Vou revisar o código e qualquer coisa volto aqui.

Rodrigo, poderia informar o por que com H2 esta ocorrendo esse erro? ou onde explica? Pois até onde eu tinha pesquisado não tinha encontrado nenhuma informaçao. Estava com o mesmo problema e a solução foi apagar a dependência do H2.

Aqui também. Eu removi a dependência do H2 e essa linha do arquivo application.proprietes

spring.jpa.hibernate.ddl-auto=update

Eu estava usando ela e o H2 por já ter desenvolvido uma aplicação com eles, porém não havia implementado a autenticação nela.

solução!

O problema é o H2 mesmo. Ele será utilizado na aula de testes automatizados, para realizar os testes das interfaces repository.

Ao adicionar o H2 no projeto o erro já acontece, pois ele inclui o console web que permite acesso ao banco de dados via navegador. Esse console é feito via uma classe Servlet do H2 e isso causa um conflito nas configurações de segurança das novas versões do Spring Security.

Para resolver o problema, sem remover o H2 do projeto, vocês devem desabilitar o console do H2 no application.properties:

spring.h2.console.enabled=false

Obs: Não cheguei a testar se apenas isso resolve ou se precisa de mais configurações.

Eu fiz assim no meu, brother:

Classe SecurityConfigurations.java

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf(csrf -> csrf.disable())
                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize.requestMatchers(HttpMethod.POST, "/login").permitAll().anyRequest().authenticated())
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

Eu estava apanhando com essa forma de fazer, pq sem o addFilterBefore (que peguei do seu código), só o /login estava funcionando aqui. Os demais endpoints nem eram alcançados.

O Seu addFilterBefore resolveu aqui para mim.

Espero que o meu authorizeHttpRequests() resolva aí para vc também.

Abs

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http.csrf(csrf -> csrf.disable())
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(req -> {
                req.requestMatchers(HttpMethod.POST, "/login").permitAll();
                req.anyRequest().authenticated();
            })
            .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
}