让我们看看 Spring 的执行身份验证的类,它是
/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java
private boolean postOnly = true;
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
当它需要一个 POST 请求时,您正在发送一个带有 /jspring_security_check?j_username=X&j_password=Z 的 GET 请求。
请求必须是带有 Content-Type 'application/x-www-form-urlencoded' 和两个参数的 POST 请求。请求正文不应是 JSON 对象。
我建议重新设计您的登录,不要使用 Ajax。
j_spring_security_check 并非设计为通过 Ajax 从登录页面调用。它旨在接受来自 HTML 表单的 POST 请求,然后在 HTTP 响应中呈现应用程序主页以提交登录表单。
j_spring_security_check 所做的是对用户进行身份验证,如果身份验证成功,它会创建一个会话并将用户重定向到主屏幕,否则它将用户重定向到“登录失败”屏幕。 j_spring_security_check 返回 302 HTTP 代码,这是一个重定向。
RESTful 登录是可能的,但您必须配置 j_spring_security_check 以不使用成功(或失败)登录视图进行响应,而是使用 JSON,因此您必须在 Java 端编写自定义登录处理程序。我做过一次,这使得代码(Java 和 ExtJS)变得如此复杂,以至于我退回到基于表单的登录。毕竟,Facebook 和 Google 使用表单提交登录,这很正常。在我的情况下,切换到 Ajax REST 登录是不值得的。
表单提交的另一个优点是网络浏览器可以记住登录名和密码,这是基于 Ajax 的登录无法做到的,我认为这就是 Google 和 Facebook 都使用表单提交的原因。
但是,如果您决定仍然需要基于 Ajax 的登录(由于实现的复杂性以及用户体验会因浏览器的密码管理器不工作而受到损害),那么您将不得不创建两个 Spring MVC 控制器,一个用于成功登录 (loginSucessController),另一个用于登录失败 (loginFailureController),两个控制器都应返回带有登录状态的统一 JSON 响应。然后配置 Spring Security 使用上面的两个控制器
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<sec:http>
<sec:intercept-url pattern="/**"/>
<sec:http-basic/>
<sec:form-login default-target-url="/loginSucessController" authentication-failure-url="/loginFailureController"/>
<sec:logout/>
</sec:http>
</beans>
当然,您必须为 loginSucessController 和 loginFailureController 创建映射和实现,我跳过了那部分。
loginSucessController 应该返回
{ "loginStatus": 1 }
并且 loginFailureController 应该返回
{ "loginStatus": 0 }
您还必须创建第三个 MVC 控制器来检测用户是否已经登录,以决定当用户返回应用程序网页时是否必须显示登录表单,请使用 org.springframework.security。 core.context.SecurityContextHolder#getContext