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

Springboot 2.7 injetar authenticationManager sem o WebSecurityConfigurerAdapter

Olá! Estou utilizando a versão 2.7.0 do springboot e para esta versão WebSecurityConfigurerAdapter não é mais usado, está deprecado. Dessa maneira, não consigo dar override no método authenticationManager. Não consigo evoluir no módulo 4 (Gerando token jwt) e vídeo 3. Segue o código do SecurityConfigurations.java

@EnableWebSecurity
@Configuration
public class SecurityConfigurations {

    @Autowired
    PasswordEncoder passwordEncoder;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth ) throws Exception {
       return auth.userDetailsService(userDetailsService())
                  .passwordEncoder(passwordEncoder()).and().build();
    }

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.builder()
            .passwordEncoder(passwordEncoder::encode)
            .username("admin")
            .password("admin")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .antMatchers("/h2-console/*").permitAll()
        .antMatchers("/auth").permitAll()
        .anyRequest().authenticated()
        .and().csrf().disable()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .antMatchers("/h2-console/*",
                        "/configuration/**",
                        "/swagger-resources/**");
    }
}

Ao tentar subir o server, tomo um erro e uma possível solução, como mostrado abaixo:

Description:

Field tokenService in br.com.sankhya.packagerepository.controllers.AutenticacaoController required a bean of type 'br.com.sankhya.packagerepository.config.TokenService' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'br.com.sankhya.packagerepository.config.TokenService' in your configuration.

Minha classe TokenService:


public class TokenService {

    @Value("${sankhya.package.repository.jwt.expiration}")
    private String expiration;

    @Value("${sankhya.package.repository.jwt.secret}")
    private String secret;

    public String gerarToken(Authentication authenticate) {
        Usuario logado = (Usuario) authenticate.getPrincipal();
        Date hoje = new Date();
        Date dataExpiracao = new Date(hoje.getTime() + Long.parseLong(expiration));

        return Jwts.builder()
            .setIssuer("Spring Introduction")
            .setSubject(logado.getId().toString())
            .setIssuedAt(hoje)
            .setExpiration(dataExpiracao)
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }

}

Minha classe AutenticacaoControler:

package br.com.sankhya.packagerepository.controllers;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import br.com.sankhya.packagerepository.config.TokenService;
import br.com.sankhya.packagerepository.controllers.dto.TokenDto;
import br.com.sankhya.packagerepository.controllers.form.LoginForm;

@RestController
@RequestMapping("/auth")
public class AutenticacaoController {

    @Autowired
    private AuthenticationManager authManager;

    @Autowired
    private TokenService tokenService;

    @PostMapping
    public ResponseEntity<TokenDto> autenticar(@RequestBody @Valid LoginForm form) {
        UsernamePasswordAuthenticationToken dadosLogin = form.converter();
        try {
            Authentication authenticate = authManager.authenticate(dadosLogin);
            String token = tokenService.gerarToken(authenticate);
            return ResponseEntity.ok(new TokenDto(token, "Bearer"));
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }

    }
}
7 respostas

Oi Felipe,

Declara esse método na classe SecurityConfigurations:

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

Já tinha tentado com esse método, mesmo resultado. Segue a saída:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field tokenService in br.com.sankhya.packagerepository.config.SecurityConfigurations required a bean of type 'br.com.sankhya.packagerepository.config.TokenService' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'br.com.sankhya.packagerepository.config.TokenService' in your configuration.

O problema agora é que você está injetando o TokenService no seu controller, mas esse service não pode ser injetado pois não tem anotações do Spring na classe.

Em qual controller? AutenticacaoController.java? No vídeo vc injeta para que seja possível pegar o token gerado. Ou estou enganado?

Esse é o meu repositório: https://github.com/felipe-yuri/springboot-introduction

solução!

Ah eu confundi com outra classe. Na verdade então na sua classe TokenService está faltando adicionar a anotação @Service e por isso acontece o erro.

Deu certo com a anotação acima.

A classe SecurityConfigurations ficou assim:

@EnableWebSecurity
@Configuration
public class SecurityConfigurations {

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UsuarioRepository usuarioRepository;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

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

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.builder()
            .passwordEncoder(passwordEncoder::encode)
            .username("admin")
            .password("admin")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .antMatchers("/h2-console/*").permitAll()
        .antMatchers("/auth").permitAll()
        .anyRequest().authenticated()
        .and().csrf().disable()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().addFilterBefore(new AutenticacaoTokenFilter(tokenService, usuarioRepository), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
//    @Bean
//    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//        http.authorizeRequests()
//        .antMatchers("/h2-console/*").permitAll()
//        .antMatchers("/auth").permitAll()
//        .anyRequest().authenticated()
//        .and().csrf().disable()
//        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//        
//        return http.build();
//    }
//    @Bean
//    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//        http.authorizeRequests()
//        .antMatchers("/h2-console/*").permitAll()
//        .anyRequest().authenticated()
//        .and().formLogin();
//        
//        return http.build();
//    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .antMatchers("/h2-console/*",
                        "/configuration/**",
                        "/swagger-resources/**");
    }
}

E a classe TokenService ficou assim:

@Service
public class TokenService {

    @Value("${sankhya.package.repository.jwt.expiration}")
    private String expiration;

    @Value("${sankhya.package.repository.jwt.secret}")
    private String secret;

    public String gerarToken(Authentication authenticate) {
        Usuario logado = (Usuario) authenticate.getPrincipal();
        Date hoje = new Date();
        Date dataExpiracao = new Date(hoje.getTime() + Long.parseLong(expiration));

        return Jwts.builder()
            .setIssuer("Spring Introduction")
            .setSubject(logado.getId().toString())
            .setIssuedAt(hoje)
            .setExpiration(dataExpiracao)
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }

    public boolean isTokenValido(String token) {
        try {
            Jwts.parser().setSigningKey(this.secret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public Long getIdUsuario(String token) {
        Claims body = Jwts.parser().setSigningKey(this.secret).parseClaimsJws(token).getBody();
        return Long.parseLong(body.getSubject());
    }

}

Obrigado pela disponibilidade @Rodrigo Ferreira!