I have implemented Spring Security to my project, but I am getting status 405 when I try to log in. I have already added csrf
token in the form
.
This is the error I am getting when I send username and password:
HTTP Status 405 - Request method 'POST' not supported
Spring version: 4.0.2.RELEASED
<div class="login-form"> <c:url var="loginUrl" value="/login" /> <form action="${loginUrl}" method="post" class="form-horizontal"> <c:if test="${param.error != null}"> <div class="alert alert-danger"> <p>Invalid username and password.</p> </div> </c:if> <c:if test="${param.logout != null}"> <div class="alert alert-success"> <p>You have been logged out successfully.</p> </div> </c:if> <div class="input-group input-sm"> <label class="input-group-addon" for="username"> <i class="fa fa-user"></i> </label> <input type="text" class="form-control" id="username" name="clientusername" placeholder="Enter Username" required> </div> <div class="input-group input-sm"> <label class="input-group-addon" for="password"> <i class="fa fa-lock"></i> </label> <input type="password" class="form-control" id="password" name="clientpassword" placeholder="Enter Password" required> </div> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <div class="form-actions"> <input type="submit" class="btn btn-block btn-primary btn-default" value="Log in"> </div> </form> </div>
Security Configuration:
@Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("G2BUserDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/home").permitAll() .antMatchers("/admin/**").access("hasRole('ADMIN')") .and().formLogin().loginPage("/login") .usernameParameter("clientusername").passwordParameter("clientpassword") .and().csrf() .and().exceptionHandling().accessDeniedPage("/Access_Denied"); // .and().csrf().disable(); }
Controller:
@RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView loginPage() { return new ModelAndView("login"); } @RequestMapping(value="/logout", method = RequestMethod.GET) public String logoutPage (HttpServletRequest request, HttpServletResponse response) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null){ new SecurityContextLogoutHandler().logout(request, response, auth); } return "redirect:/login?logout"; } @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET) public ModelAndView accessDeniedPage(ModelMap model) { model.addAttribute("user", getPrincipal()); return new ModelAndView("accessDenied"); } @RequestMapping(value = "/admin", method = RequestMethod.GET) public ModelAndView adminPage(ModelMap model) { model.addAttribute("user", getPrincipal()); return new ModelAndView("admin"); } private String getPrincipal(){ String userName = null; Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserDetails) { userName = ((UserDetails)principal).getUsername(); } else { userName = principal.toString(); } return userName; }
Almost every topic about this issue says that we need to add csrf
token, but I already added. Am I missing something?
Advertisement
Answer
You can set two endpoints for one url. But you cannot set any request parameter as required. As I saw your request map for login, you can set your request method like this:
@RequestMapping(value = "/login", method = { RequestMethod.GET, RequestMethod.POST }) public ModelAndView loginPage() { return new ModelAndView("login"); }