5
respostas

Não estou conseguindo implementar essa autenticação em memória

Estou usando o Java 11. Eu simplesmente não estou conseguindo implementar essa funcionalidade de login em memória. Ocorre erro. Alguém pode me dizer se a implementação real de login, com o banco de dados, é bem diferente dessa implementação, de forma que eu não obterei um erro dessa natureza ? De qualquer jeito, segue uma parte da stacktrace do erro e o meu projeto: https://github.com/Adriano-Ivan/mudi

OBS: procurei tirar a extensão 'WebSecurityConfigurerAdapter' da classe e o override e parou de acontecer o erro no console, mas em compensação é gerada uma tela de login aleatória que eu nem implementei e quando tento fazer um login com user e password corretos, o login não dá certo, mostrando um erro quando estão errados os dados, e simplesmente não abrindo quando estão corretos. Eu achei esse comportamento muito peculiar... Além disso, já adicionei várias dependências que, segundo alguns fóruns, são necessárias, e já fiz vários updates no maven project, e nada disso resolveu.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: permitAll only works with HttpSecurity.authorizeRequests()
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.14.jar:5.3.14]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.14.jar:5.3.14]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-2.6.2.jar:2.6.2]
    at b
5 respostas

Consegui resolver o erro principal da seguinte forma:

1) Adicionando essa dependência:

        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.5.0</version>
        </dependency>

2) Deixando o código do WebSecurityConfig assim:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig{

    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeHttpRequests()
            .anyRequest().authenticated()
        .and()
        .formLogin(form ->
            form.loginPage("/login")
            .permitAll()
            );
    }

    @Bean

    public UserDetailsService userDetailsService() {
        UserDetails user = User
                .withDefaultPasswordEncoder()
                .username("w77")
                .password("11")
                .roles("ADM")
                .build();

        return new InMemoryUserDetailsManager(user);
    }
}

Porém, ainda ocorre algo indesejado. Continuo recebendo uma tela de login meio bizarra: Tela de login com fundo cinza, formulário centralizado com dois campos (usuário e senha) e título 'Please sign in' !

Pelo visto, é preciso autorizar o acesso a certos caminhos. Após muita pesquisa, consegui solucionar com esse código:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
            .authorizeRequests()
                .antMatchers(
                        "/bootstrap/**").permitAll() 
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll();
    }
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user = User
                .withDefaultPasswordEncoder()
                .username("w77")
                .password("11")
                .roles("ADM")
                .build();

        return new InMemoryUserDetailsManager(user);
    }
}

Mas o problema ainda não está solucionado, pois, após o login, sou direcionado para a raiz, onde não há nada e portanto ocorre erro, e só consigo chegar à página home se eu digitar na url.

Pronto. Consegui deixar como desejado com esse código:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers(
                        "/bootstrap/**").permitAll() 
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .permitAll();
    }
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user = User
                .withDefaultPasswordEncoder()
                .username("w77")
                .password("11")
                .roles("ADM")
                .build();

        return new InMemoryUserDetailsManager(user);
    }
}

Continuou apresentando erros no redirecionamento, mas consegui uma solução ao definir uma rota raiz para a home. Quando tiver certeza de que está funcionando mesmo, após mais alguns testes, coloco o tópico como resolvido. Enquanto isso, se alguém tiver outra solução, por favor compartilhe.

@Controller
@RequestMapping("/")
public class HomeController {

    @Autowired
    private PedidoRepository pedidoRepository;

    @GetMapping
    public String root(Model model) {
        List<Pedido> pedidos = pedidoRepository.findAll();
        model.addAttribute("pedidos",pedidos);

        return "home";
    }

    @GetMapping("/home")
    public String home(Model model) {
        List<Pedido> pedidos = pedidoRepository.findAll();
        model.addAttribute("pedidos",pedidos);

        return "home";
    }
    @GetMapping("/home/{status}")
    public String aguardando(@PathVariable("status") String status,Model model){
        List<Pedido> pedidos = pedidoRepository.findByStatus(StatusPedido.valueOf(status.toUpperCase()));
        model.addAttribute("pedidos",pedidos);
        model.addAttribute("status",status);
        return "home";
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String onError() {
        return "redirect:/home";
    }
}

Olá Adriano, tudo bem?

Pelo que entendi, você está tentando implementar a funcionalidade de login em memória no seu projeto Spring MVC, mas está enfrentando alguns problemas. Pelo erro que você postou, parece que há um problema com a configuração do Spring Security, mais especificamente com a configuração do HttpSecurity.

Uma possível solução seria adicionar o método "authorizeRequests()" na configuração do HttpSecurity, como o erro sugere. Ficaria mais ou menos assim:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/login").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/home")
        .permitAll()
        .and()
        .logout()
        .permitAll();
}

Quanto à sua pergunta sobre a implementação de login com banco de dados, ela é um pouco mais complexa do que a implementação em memória, mas não necessariamente mais difícil. A principal diferença é que você precisará configurar o Spring Security para se comunicar com o seu banco de dados, seja ele relacional ou não.

Para isso, você pode utilizar o JDBC Authentication do Spring Security, que é uma forma de autenticação baseada em JDBC. Há também outras opções, como o Spring Data JPA, que permite uma integração mais fácil com bancos de dados relacionais.

Espero ter ajudado e bons estudos!