我正在尝试使用通过Ajax提交的登录表单来实现Spring Security。我创建了自己的自定义authenticationFailureHandler和我自己的自定义authenticationSuccessHandler。我不确定我的问题是我的Spring / Java代码还是我的客户端代码。我也看到跨站脚本保护可能导致问题。当我登录它确实很好,但我实际上得到一个新的HTML页面,其中包含我的JSON,但内容类型是html / text。
当登录失败时,我会得到同样的结果。
请求和响应标头对我来说不合适。首先没有响应头,其次请求头没有X-Requested-With。
需要注意的一些事项
这是登录表单的样子:
以下是我的自定义处理程序
@Component
public class AuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Autowired
private UserMapper userMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
userMapper.incrementFailedLogin(request.getParameter("sec-user"));
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().print("{\"success\": false}");
response.getWriter().flush();
}
}
-
@Component
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Autowired
private UserMapper userMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
userMapper.updateUserOnAuthSuccess(request.getParameter("sec-user"));
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print("{\"success\": true}");
response.getWriter().flush();
}
}
我的Spring Security配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
AuthFailureHandler authFailureHandler;
@Autowired
AuthSuccessHandler authSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/about","/public/**").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.usernameParameter("sec-user")
.passwordParameter("sec-password")
.failureHandler(authFailureHandler)
.successHandler(authSuccessHandler)
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.deleteCookies("remember-me", "JSESSIONID")
.permitAll()
.and()
.rememberMe();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
登录表格(Thymeleaf) - 嵌入在导航菜单中
<div th:fragment="login">
<form th:action="@{/login}" method="post" accept-charset="UTF-8" class="login-pane" id="login-form">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="form-group">
<label for="sec-user">Email</label>
<input type="email" class="form-control" id="sec-user" name="sec-user" placeholder="Email" />
</div>
<div class="form-group">
<label for="sec-password">Password</label>
<input type="password" class="form-control" id="sec-password" name="sec-password" placeholder="Password" />
</div>
<button type="login-btn" class="btn btn-danger">Login</button>
</form>
</div>
最后但并非最不重要的是我的javascript代码
$(document).ready(function() {
$("#login-btn").click(login)
});
function login() {
console.info("Attempting to authenticate");
$.ajax({
type: 'POST',
url: '/login',
data: $('#login-form').serialize(),
cache: false,
dataType: "json",
crossDomain: false,
success: function (data) {
var response = jQuery.parseJSON(data);
if (response.success == true) {
console.info("Authentication Success!");
window.location.href("/");
}
else {
console.error("Unable to login");
}
},
error: function (data) {
console.error("Login failure");
}
});
}
答案 0 :(得分:1)
您没有调用在javascript中定义但实际在登录表单中发布到 login 操作的 login()方法。
删除帖子操作调用,并在Login按钮的 onclick 事件中调用 login()方法。