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

Request method 'POST' not supported

Após toda configuração quando faço o login tenho o erro: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported

minha configuração

http.authorizeRequests()
            .antMatchers("/assets/**", 
                    "/fonts/**",
                    "/global/**", 
                    "/imagens/**", 
                    "/auth/**").permitAll()
            .anyRequest().authenticated()
        .and()
            .formLogin()
            .loginPage("/auth/form")
            .failureUrl("/auth/login?error=true")
            .usernameParameter("j_username")
            .passwordParameter("j_passsword")
            .permitAll()
        .and()
            .logout()
            .logoutSuccessUrl("/auth/login?logout=true")
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
        .and()
            .exceptionHandling().accessDeniedPage("/auth/denied");

Controller de acesso:

@Controller
@RequestMapping(value = "auth")
public class LoginController {

    @RequestMapping(value = "/form", method = RequestMethod.GET)
    public String loginPage(){
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView login(
            @RequestParam(value = "error", required = false) boolean error,
            @RequestParam(value = "error", required = false) boolean logout, ModelMap model
            ){
        System.out.println("===========");

        if(error){
            model.addAttribute("error", "Login inválido, senha ou nome do usuário não confere.");
        return new ModelAndView("login", model);
        }

        if(logout){
            model.addAttribute("logout", "Deslogado com sucesso");
            return new ModelAndView("login", model);
        }

        return new ModelAndView("redirect:/");
    }

    @RequestMapping(value = "/denied", method = RequestMethod.GET)
    public ModelAndView acessoNegado(){

        return new ModelAndView("error", "mensagem", "Acesso negado");
    }
}

jsp

<c:url value="/auth/login" var="loginUrl"/>
      <form method="POST" action="${loginUrl }">

          <c:if test="${error != null}">
              ${error}
          </c:if>
           <c:if test="${logout != null}">
              ${logout}
          </c:if>
        <!-- <div class="form-group">
          <label class="sr-only" for="inputName">Nome</label>
          <input type="text" class="form-control" id="inputName" name="j_username" placeholder="Name">
        </div> -->
        <div class="form-group">
          <label class="sr-only" for="inputEmail">Email</label>
          <input type="email" class="form-control" id="inputEmail" name="j_username" placeholder="Email">
        </div>
        <div class="form-group">
          <label class="sr-only" for="inputPassword">Senha</label>
          <input type="password" class="form-control" id="inputPassword" name="j_password"
          placeholder="Password">
        </div>
        <div class="form-group clearfix">
          <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token }"/>
          <div class="checkbox-custom checkbox-inline checkbox-primary float-left">
            <input type="checkbox" id="inputCheckbox" name="remember">
            <label for="inputCheckbox">Lembrar</label>
          </div>
          <a class="float-right" href="forgot-password.html">Esqueci minha senha!</a>
        </div>
        <button type="submit" class="btn btn-primary btn-block">Enviar</button>
      </form>
12 respostas

pelo login padrão do spring consigo fazer o login tranquilamente, mas como o meu não!

        http.authorizeRequests()
            .antMatchers("/assets/**", 
                    "/fonts/**",
                    "/global/**", 
                    "/imagens/**", 
                    "/auth/**").permitAll()
            .anyRequest().authenticated()
        .and()
            .formLogin()
            /*.loginPage("/auth/form")
            .failureUrl("/auth/login?error=true")
            .usernameParameter("username")
            .passwordParameter("passsword")
            .permitAll()
        .and()
            .logout()
            .logoutSuccessUrl("/auth/login?logout=true")
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
        .and()
            .exceptionHandling().accessDeniedPage("/auth/denied")*/;

Ola Clerman, o problema ocorre pois no seu controller voce indicou que que aceita apenas metodos GET, mas voce está fazendo um post na sua tela de login:

Na anotacao @RequestMapping, troca o atributo method para RequestMethod.POST, conforme abaixo:

@RequestMapping(value = "/login", method = RequestMethod.POST)
    public ModelAndView login(
            @RequestParam(value = "error", required = false) boolean error,
            @RequestParam(value = "error", required = false) boolean logout, ModelMap model
            )

Ok, aparentemente esta certo, mas ao fazer o login o redirecionamento volta ao login

pelo login padrão do spring consigo fazer o login tranquilamente, mas como o meu não! Como posso resolver?

Olá Clerman, ele retorna a tela de login pois é necessário avisar o spring que o usuário está logado, mas nesse caso usar o controller nao vai dar muito certo, o correto é criar um novo provider de autenticação do spring. Nesse projeto do github tem um exemplo de como implementar:

https://github.com/denisricci/treld-blog-api/blob/master/src/main/java/br/com/treld/config/security/SpringSecurityConfig.java

Se é que eu entendi bem a sua resposta Denis, minha intenção é justamente utilizar o controller para customizar completamente a tela de login, erros e todos os retornos do login para o usuário, não quero utilizar o padrão, preciso saber por que não estou conseguindo acessar com meu login customizado e com o padrão estou conseguindo?

Olá Clerman,

Eu entendi que voce deseja customizar totalmente a tela de login, porém utilizar o controller não é o melhor caminho, conforme eu falei, o spring precisa ficar sabendo que o usuário está logado e precisa criar uma sessao para ele, para fazer isso, voce terá que criar um Autenticator Provider e indicar ao spring como ele deve autenticar o usuário, voce pode criar sua propria pagina de login, mas deve enviar os dados utilizando o próprio endpoint do spring.

Infelizmente eu nao tenho um exemplo melhor para te passar, mas repare que na classe abaixo, a busca to usuário é totalmente customizada, mas é necessario indicar ao Spring utilizar essa classe para fazer a autenticacao.

@Service
public class MongoDBAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private static final Logger LOG = LoggerFactory.getLogger(MongoDBAuthenticationProvider.class);

    @Autowired
    private AuthorRepository authorRepository;


    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        Assert.notNull(userDetails.getPassword(), "Password of user " + userDetails.getUsername() + " is null");

        String password = authentication.getCredentials().toString();

       if(!CryptographyUtils.checkEquality(password, userDetails.getPassword())){
           throw new UsernameNotFoundException("Authentication Failed");
       }

    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

        User author = authorRepository.findByUsername(username);

        if(author == null){
            String errorMessage = "Author with username " + username + " not found";
            LOG.debug(errorMessage);
            throw new UsernameNotFoundException(errorMessage);
        }

        return new AuthorUserDetails(author);
    }
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private CustomAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private CustomAuthenticationFailureHandler restAuthenticationFailureHandler;

    @Autowired
    private MongoDBAuthenticationProvider authenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws TreldException {
        try{
            http.
                    csrf().disable().
                    exceptionHandling().
                    authenticationEntryPoint(restAuthenticationEntryPoint).
                    and().formLogin().
                    successHandler(customAuthenticationSuccessHandler).
                    failureHandler(restAuthenticationFailureHandler);
        }catch(Exception e){
            throw new TreldException(e);
        }
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws TreldException {
        try{
            auth.authenticationProvider(authenticationProvider);
        }catch(Exception e){
            throw new TreldException(e);
        }
    }
}

Denis Ricci fico grato mas, fico com receio de utilizar a forma que propunha, pois vou ter que encaixar essa MongoDBAuthenticationProvider e criar todas essas outras classes para injetar na classe de configuração, ficaria ruim de desse algum bug, ou algum erro, devido a minha pouca experiência ainda fico com essa insegurança!

Sem problemas Clerman,

Lembrando que o MongoDBAuthentication é apenas um exemplo, se voce pesquisar um pouco na internet voce encotrara outros exemplos de como implementar o seu login.

Quando altero para o login padrão do Spring, funciona normalmente. Tem um outra sugestão do que posso fazer?

http.authorizeRequests() .antMatchers("/assets/", "/fonts/", "/global/", "/imagens/", "/usuario/", "/auth/", "/usuario/").permitAll() .antMatchers("/").hasAnyAuthority("VISITANTE") .anyRequest().authenticated() .and() .formLogin() //.loginPage("/auth/login") //.failureUrl("/auth/login?error=true") //.usernameParameter("j_username") //.passwordParameter("j_passsword") .permitAll() .and() .logout() .logoutSuccessUrl("/auth/login?logout=true") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .and() .exceptionHandling().accessDeniedPage("/auth/denied");

Denis encontrei uma solução aqui mas não encontrei o problema que acho que esta no ModelAndView (acho!), pois troquei os métodos e o form e ainda alterei a configuração no form, gostaria de entender o que ocorreu? Se puder ajudar!

@Controller
//@RequestMapping(value = "auth")
public class LoginController {

    /*@RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginPage(){
        return "login";
    }*/

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(Model model, String error, String logout) {
        if (error != null)
            model.addAttribute("error", "Nome de usuário ou senha inválidos.");

        if (logout != null)
            model.addAttribute("messagem", "Você foi deslogado com sucesso.");

        return "login";
    }

    /*@RequestMapping(value = "/login", method = RequestMethod.POST)
    public ModelAndView login(
            @RequestParam(value = "error", required = false) boolean error,
            @RequestParam(value = "error", required = false) boolean logout, ModelMap model
            ){
        if(error){
            model.addAttribute("error", "Login inválido, senha ou nome do usuário não confere.");
        return new ModelAndView("login", model);
        }

        if(logout){
            model.addAttribute("logout", "Deslogado com sucesso");
            return new ModelAndView("login", model);
        }

        return new ModelAndView("redirect:/");
    }*/

    /*@RequestMapping(value = "/denied", method = RequestMethod.GET)
    public ModelAndView acessoNegado(){

        return new ModelAndView("error", "mensagem", "Acesso negado");
    }*/
}
<form method="POST" action="/financeiro/login">
        <div class="form-group ${error != null ? 'has-error' : ''}">
            <span>${messagem}</span>
            <input name="username" type="text" class="form-control" placeholder="Nome"
                   autofocus="true"/>
            <input name="password" type="password" class="form-control" placeholder="Senha"/>
            <span>${error}</span>
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

            <button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
        </div>
    </form>
http.authorizeRequests()
            .antMatchers("/assets/**", "/fonts/**", "/global/**", "/imagens/**", "/usuario/**", "/auth/**", "/usuario/**").permitAll()
            .antMatchers("/**").hasAnyAuthority("VISITANTE")
            .anyRequest().authenticated()
        .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
        .and()
            .logout()
            .logoutSuccessUrl("/login")
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
        .and()
            .exceptionHandling().accessDeniedPage("/denied");
    }
solução!

Olá Clerman,

Seu método esta mapeado para receber requisicoes GET porém voce esta fazendo um POST para o endpoint.