I am trying to implement Spring Security with the login form being submitted via Ajax. I have created my own custom authenticationFailureHandler and my own custom authenticationSuccessHandler. I'm not sure if my issue lies in my Spring / Java code or on my client side code. I've also seen the cross site scripting protection could be causing the issue. When I login it does authenticate fine, but i actually get a new HTML page with my JSON on it but the content type is html/text.
When the login is unsuccessful I get the same thing.
The Request and Response Headers do not look right to me. First there are no response headers, and secondly the request headers does not have X-Requested-With.
Some items to note
- I am using Spring Boot 1.2.5
- I have CSRF enabled in Spring Security, it is a requirement from client
- There cannot be a login page, the login must be in the top right of the top navigation / header, hence why I am submitted the from via JS/Ajax
This is what the login form will look like:
Here are my custom handlers
@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();
}
}
My Spring Security config
@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());
}
}
Login Form (Thymeleaf)- embedded in navigation menu
<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>
And last but not least my javascript code
$(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");
}
});
}
Aucun commentaire:
Enregistrer un commentaire