我已经查看了我能找到的每个相关问题,但未能找到适用于我的场景的答案。我正在使用Spring WebSecurityConfigurerAdapter,我能够对单个用户类型进行身份验证,但在配置我的SecurityConfig类以处理多个用户类型之后,我得到了“不支持请求方法'POST'”错误,即使我仍然formLogin()。loginPage(URL ...)的相同URL。
我有4个静态类的订单1,2,3和4,虽然前2个只是允许未经身份验证的用户使用模式/
用于家庭和/account/*
用于其他事项的URL。所有这些静态类都正常工作,当使用模式/company/*
和/candidate/*
访问URL时,用户将被定向到相应的登录页面进行登录。
这就是现在出现问题的地方。我使用“/ account / candidateLogin”和“/ account / companyLogin”作为formLogin()。loginPage(arg)中的args,但我之前使用的相同控制器方法不再正常工作。我收到405错误,控制台显示o.s.web.servlet.PageNotFound : Request method 'POST' not supported
。
以下是相关代码,并提前感谢您:
security config.Java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers( "/images/**",
"/vendor/**",
"/app.css",
"/app.js",
"/favicon.png");
}
@Configuration
@Order(1)
public static class HomePageSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/")
.authorizeRequests().anyRequest().permitAll();
}
}
@Configuration
@Order(2)
public static class AccountSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/account/*")
.authorizeRequests().anyRequest().permitAll();
}
}
@Configuration
@Order(3)
public static class CompanySecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
@Autowired
private CompanyService companyService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(companyService);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/company/*")
.authorizeRequests()
.anyRequest()
.hasRole("COMPANY")
.and()
.formLogin()
.loginPage("/account/companyLogin")
.successHandler(companyLoginSuccessHandler())
.failureHandler(companyLoginFailureHandler())
.and()
.logout()
.logoutSuccessUrl("/");
}
public AuthenticationSuccessHandler companyLoginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/company/companyProfile");
}
public AuthenticationFailureHandler companyLoginFailureHandler() {
return (request, response, exception) -> {
request.getSession().setAttribute("flash", new FlashMessage("Incorrect username and/or password. Please try again.", FlashMessage.Status.FAILURE));
response.sendRedirect("/account/companyLogin");
};
}
}
@Configuration
@Order(4)
public static class CandidateSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private CandidateService candidateService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(candidateService);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/candidate/*")
.authorizeRequests()
.anyRequest()
.hasRole("CANDIDATE")
.and()
.formLogin()
.loginPage("/account/candidateLogin")
.successHandler(candidateLoginSuccessHandler())
.failureHandler(candidateLoginFailureHandler())
.and()
.logout()
.logoutSuccessUrl("/");
}
public AuthenticationSuccessHandler candidateLoginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/candidate/candidateProfile");
}
public AuthenticationFailureHandler candidateLoginFailureHandler() {
return (request, response, exception) -> {
request.getSession().setAttribute("flash", new FlashMessage("Incorrect username and/or password. Please try again.", FlashMessage.Status.FAILURE));
response.sendRedirect("/account/candidateLogin");
};
}
}
}
用于登录URI的控制器。这些是相同的,只有一个用于候选登录,一个用于公司
@Controller()
public class AccountController {
@Autowired
private CandidateService candidateService;
@Autowired
private CompanyService companyService;
@RequestMapping(value = "/account/candidateLogin", method = RequestMethod.GET)
public String candidateLoginForm(Model model, HttpServletRequest request) {
model.addAttribute("candidate", new Candidate());
try {
Object flash = request.getSession().getAttribute("flash");
model.addAttribute("flash", flash);
model.addAttribute("action", "/account/candidateLogin");
model.addAttribute("submit","Login");
request.getSession().removeAttribute("flash");
} catch (Exception e) {
//Flash session attribute must not exist. Do nothing and proceed.
}
return "account/candidateLogin";
}
@RequestMapping(value = "/account/companyLogin", method = RequestMethod.GET)
public String loginCompanyForm(Model model, HttpServletRequest request) {
model.addAttribute("company", new Company());
try {
Object flash = request.getSession().getAttribute("flash");
model.addAttribute("flash", flash);
model.addAttribute("action", "/account/companyLogin");
model.addAttribute("submit","Login");
request.getSession().removeAttribute("flash");
} catch (Exception e) {
//Flash session attribute must not exist. Do nothing and proceed.
}
return "account/companyLogin";
}
登录HTML文件。我只是包括一个,因为唯一的区别是变量名称。
<!DOCTYPE html>
<html lang="en">
<head th:replace="layout :: head('explore')"></head>
<body>
<div th:replace="layout :: nav"></div>
<div th:replace="layout :: login"></div>
<h1 style="margin-left: 25%">Company Login</h1>
<div class="grayContainer">
<div th:fragment="login">
<div class="row">
<div class="col s12">
<div th:replace="layout :: flash"></div>
<form th:action="@{${action}}" th:object="${company}" method="post">
<div class="input-field" style="width: 70%; margin: 0 auto;">
<input type="text" th:field="*{username}" placeholder="Username/Email"/>
</div>
<div class="input-field" style="width: 70%; margin: 0 auto;">
<input type="password" th:field="*{password}" placeholder="Password"/>
</div>
<button class="button" type="${submit}" style="text-align: center;">Login</button>Forgot password?
</form>
</div>
</div>
</div>
</div>
<div th:replace="layout :: scripts"></div>
</body>
编辑
正如一些人建议的那样,我将登录表单的请求映射中的方法更改为POST而不是GET并启用了安全日志记录。现在我根本无法访问登录页面,它给我一个405错误,这是安全调试器日志:
************************************************************
2018-03-06 14:27:48.820 INFO 4495 --- [nio-8080-exec-4] Spring Security Debugger :
************************************************************
Request received for GET '/account/candidateLogin':
org.apache.catalina.connector.RequestFacade@4cf3f981
servletPath:/account/candidateLogin
pathInfo:null
headers:
host: localhost:8080
connection: keep-alive
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
referer: http://localhost:8080/account/selectType
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cookie: JSESSIONID=58FD34AB4F9796EC523C355C0A51ED49
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-03-06 14:27:48.829 WARN 4495 --- [nio-8080-exec-4] o.s.web.servlet.PageNotFound : Request method 'GET' not supported
用于请求映射
@RequestMapping(value = "/account/candidateLogin", method = RequestMethod.GET)
和
@RequestMapping(value = "/account/companyLogin", method = RequestMethod.GET)
它们以ur形式与请求的GET方法映射
<form th:action="@{${action}}" th:object="${company}" method="post">
它的POST。
在你的java代码中,请求方法是GET,
@RequestMapping(value = "/account/companyLogin", method = RequestMethod.GET)
在你的HTML代码中,请求方法是POST,
<form th:action="@{${action}}" th:object="${company}" method="post">
你应该保持一致。