自定義登入和登出頁面

无涯子wyz發表於2024-04-22

自定義登入

在預設的情況下,Spring Security為我們生成的登入登出頁面如下:


我們可以自定義登入和登出頁面,我們使用thymeleaf來編寫登入頁面,程式碼如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Please Log In</title>
</head>
<body>
<h1>Please Log In</h1>
<form th:action="@{/login}" method="post">
    <div>
        <input type="text" name="username" placeholder="Username"/>
    </div>
    <div>
        <input type="password" name="password" placeholder="Password"/>
    </div>
    <input type="submit" value="Log in" />
</form>
</body>
</html>

配置自定義登入相關設定:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // 認證相關
    http.authorizeRequests(authorize ->
                           authorize
                           // /login.html請求不需要驗證
                           .requestMatchers(new AntPathRequestMatcher("/login")).permitAll()
                           .anyRequest()
                           .authenticated()
                          );

    // 開啟登入表單
    http.formLogin(form -> {
        form
            // 自定義登入頁面
            .loginPage("/login")
            // 自定義登入URL
            .loginProcessingUrl("/login")
            // 登入成功之後跳轉的頁面
            .defaultSuccessUrl("/index")
            .permitAll();
    });

    // 關閉csrf防護
    http.csrf().disable();

    return http.build();
}


登入成功之後跳轉頁面:

在現在的專案開發過程中,一般都是前後端分離的專案,後端只需要返回JSON資料,由前端自己進行跳轉,那麼我們可以進行如下配置:

// 開啟登入表單
http.formLogin(form -> {
    form
        // 自定義登入頁面
        .loginPage("/login")
        // 自定義登入URL
        .loginProcessingUrl("/login")
        // 用於前後端分離的情況,登入成功之後返回JSON資料
        .successHandler(new AuthenticationSuccessHandlerImpl())
        // 用於前後端分離的情況,登入失敗之後返回JSON資料
        .failureHandler(new AuthenticationFailureHandlerImpl())
        .permitAll();
});

上面分別配置了登入成功返回的JSON和登入失敗的JSONAuthenticationSuccessHandlerImpl,AuthenticationFailureHandlerImpl分別實現Spring Security提供的介面AuthenticationSuccessHandler,AuthenticationFailureHandler

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String,Object> map = new HashMap<>();
        map.put("code", "200");
        map.put("message", "成功");
        map.put("data", authentication);
        String json = new ObjectMapper().writeValueAsString(map);

        // 構建返回
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().println(json);
    }
}
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        Map<String,Object> map = new HashMap<>();
        map.put("code", "-1");
        map.put("message", "登入失敗");
        map.put("data", exception.getLocalizedMessage());

        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().println(json);
    }
}

使用Postman測試:

自定義登出

// 登出表單
http.logout(logout -> {
    logout
        // 自定義登出地址
        .logoutUrl("/logout").
        // 使用者前後端分離登出返回JSON
        logoutSuccessHandler(new LogoutSuccessHandlerImpl());
});

實現LogoutSuccessHandler介面:

public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String,Object> map = new HashMap<>();
        map.put("code", "200");
        map.put("message", "登出成功");
        map.put("data", authentication.getName());
        String json = new ObjectMapper().writeValueAsString(map);

        response.setContentType("application/json;charset=utf-8");
        response.getWriter().println(json);
    }
}

相關文章