Spring Boot-AJAX登入

純粹紀錄使用客製化登錄頁面,然後用AJAX POST登入

因為是記錄用的,所以不多作解釋


首先先定義Success Handler與Failure Handler

Success Handler

public class AjaxAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
/// Response OK
response.setStatus(HttpServletResponse.SC_OK);
}
}

Failure Handler

public class AjaxAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
/// Response 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
}
}

再來是定義處理Exception的EntryPoint

public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {

/// Check the request is ajax
if(isAjaxRequest(request)){
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,authException.getMessage());
}
else{
response.sendRedirect("/login.html");
}

}

public static boolean isAjaxRequest(HttpServletRequest request) {
String ajaxFlag = request.getHeader("X-Requested-With");

return ajaxFlag != null && "XMLHttpRequest".equals(ajaxFlag);
}
}

最後是Security Config

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.exceptionHandling().authenticationEntryPoint(new UnauthorizedEntryPoint())
.and()
/// Disable csrf
.csrf().disable()
.authorizeRequests()
/// /login and /*.* don't need authentication
.antMatchers("/login", "/*.*").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
/// Set login form
.loginPage("/login.html")
//.loginProcessingUrl("/login")
//.usernameParameter("username")
//.passwordParameter("password")
//.successHandler(new AjaxAuthSuccessHandler())
//.failureHandler(new AjaxAuthFailureHandler())
//.permitAll()
.and()
/// Set AuthenticationFilter
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.logout()
.logoutUrl("/logout")
.permitAll();
}

@Bean
public UsernamePasswordAuthenticationFilter authenticationFilter() throws Exception {
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter();

/// Set parameter name called username
filter.setUsernameParameter("username");
// Set parameter name called password
filter.setPasswordParameter("password");
/// Only accept POST
filter.setPostOnly(true);
/// Set success handler
filter.setAuthenticationSuccessHandler(new AjaxAuthSuccessHandler());
/// Set failure handler
filter.setAuthenticationFailureHandler(new AjaxAuthFailureHandler());
/// Set request matcher
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
/// Set AuthenticationManager (Get the default AuthenticationManager)
filter.setAuthenticationManager(authenticationManagerBean());

return filter;
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
/// Normally, here needs to encrypt the password
.withUser("user").password("{noop}user").roles("USER");
}
}

configure function註解的部份其實也能用,不一定要用AuthenticationFilter

因為定義在HttpSecurity好像會幫你作,而且預設是用UsernamePasswordAuthenticationFilter

所以我寫這樣算是多此一舉吧

不過如果有需要自定義Filter的話,就能參考


再來是客製化登入頁面(很偷懶)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"></html>
<head>
<title>login </title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
</head>
<body>

<div><label> User Name : <input id="username" type="text" name="username"/> </label></div>
<div><label> Password: <input id="password" type="password" name="password"/> </label></div>
<div><input type="button" onclick="login()"/></div>

<script>
function login () {
var username = document.getElementById("username").value
var password = document.getElementById("password").value

$.ajax ({
url: "/login",
type: "POST",
data: "username=" + username + "&password=" + password,
success: function(response, textStatus, xhr) {
alert("Login in successfully");
window.location.href = "/user/index.html"
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
</script>

</body>
</html>

可以看到登入成功後,會導向/user/index.html這個頁面

再參考SecurityConfig的configure function

可以看到我只允許/login與/*.*的路徑能未經驗證的存取

所以,/user/index.html這個頁面是必須登入後才能看到的


以上就是用AJAX登入的範例

不過有些情況未解決

像是必須把csrf關掉才能登入成功

有查到thymeleaf似乎能解決,但我希望能夠前端單純就是html頁面而不用到Template

2019-06-10 07:44:42.0



吾乃一邊緣人是也