概述
上一篇文章講了,登陸完後會給我們返回信息,這沒毛病,但是問題來了,他跳轉了頁面,假設我們不想跳轉頁面,只想返回固定格式的JSON呢?這就需要我們自定義成功處理器了。失敗的情況也雷同。
一、創建登錄成功處理器LoginSuccessHandler,並重寫onAuthenticationSuccess方法
@Slf4j
@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
log.info("登錄成功!");
/* 默認:會幫我們跳轉到上一次請求的頁面上 */
//super.onAuthenticationSuccess(request, response, authentication);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
PrintWriter writer = response.getWriter();
writer.write("登錄成功");
writer.flush();
writer.close();
}
}
Spring Security完成用戶登錄後跳轉回原頁面的處理是在SavedRequestAwareAuthenticationSuccessHandler類裏面進行的,如果想要自定義登錄成功後的操作可以繼承該類,重寫該方法。爲什麼不實現AuthenticationSuccessHandler接口,而是繼承SavedRequestAwareAuthenticationSuccessHandler類的方式?因爲SavedRequestAwareAuthenticationSuccessHandler這個類記住了你上一次的請求路徑,比如:你請求user.html。然後被攔截到了登錄頁,這時候你輸入完用戶名密碼點擊登錄,會自動跳轉到user.html,而不是主頁面。
若是前後分離項目則實現接口即可,因爲我弄的是通用的權限組件,所以選擇了繼承。
一種成功的身份驗證策略,通過ExceptionTranslationFilter,默認將DefaultSavedRequest存儲在session中當這樣的請求被截獲並需要身份驗證時,在身份驗證過程開始之前存儲請求數據以記錄原始目的地(url)並允許在重定向到相同的URL時重鍵請求,如果合適的話,這個類負責執行到原始URL的重定向。
在成功進行驗證之後,它根據以下場景確定重定向目標:
- 如果alwaysUseDefaultTargetUrl屬性設置爲true,則defaultTargetUrl將用於目標.會話中存儲的任何defaultSavedRequest將被刪除。
- 如果在請求中設置了targetUrlParameter,則該值將用作目標。defaultTargetUrl將再次被刪除
- 如果在RequestCache中找到SavedRequest(由ExceptionTranslationFilter所設置,在驗證過程開始之前記錄原始目的地),將對原始目的地的Url執行重定向。當收到重定向請求時,SavedRequest對象將保持緩存狀態並被拾取(請參閱SavedRequestAwareWrapper)
- 如果找不到SavedRequest它將委託給基類(父類)。
二、創建登錄失敗處理器,並重寫onAuthenticationFailure方法
@Slf4j
@Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
/* 默認:執行重定向或轉發到defaultfailureurl(如果設置),Otherw返回401錯誤代碼 */
//super.onAuthenticationFailure(request,response,exception)
log.error("登錄錯誤 [{}] ",exception.getMessage());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
PrintWriter writer = response.getWriter();
writer.write(exception.getMessage());
writer.flush();
writer.close();
}
}
AuthenticationFailureHandler接口定義了Spring Security Web在遇到認證錯誤時所使用的處理策略。
典型做法一般是將用戶重定向到認證頁面(比如認證機制是用戶名錶單認證的情況)讓用戶再次認證。當然具體實現類可以根據需求實現更復雜的邏輯,比如根據異常做不同的處理等等。舉個例子,如果遇到CredentialsExpiredException異常(AuthenticationException異常的一種,表示密碼過期失效),可以將用戶重定向到修改密碼頁面而不是登錄認證頁面。
在Spring Security Web框架內部,缺省使用的認證錯誤處理策略是AuthenticationFailureHandler的實現類SimpleUrlAuthenticationFailureHandler。它由配置指定一個defaultFailureUrl,表示認證失敗時缺省使用的重定向地址。一旦認證失敗,它的方法onAuthenticationFailure被調用時,它就會將用戶重定向到該地址。如果該屬性沒有設置,它會向客戶端返回一個401狀態碼。另外SimpleUrlAuthenticationFailureHandler還有一個屬性useForward,如果該屬性設置爲true,頁面跳轉將不再是重定向(redirect)機制,取而代之的是轉發(forward)機制。
三、把自定義處理器加入security認證中
在SecurityConfig配置類的configure(HttpSecurity http)方法中加入我們自定義的處理Handler
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //需要授權的請求
.antMatchers("/login","/home").permitAll() //過濾不需要認證的路徑
.anyRequest().authenticated() //對任何一個請求,都需要認證
.and() //完成上一個配置,進行下一步配置
//.httpBasic();
.formLogin() //配置表單登錄
.loginPage("/login") //設置登錄頁面
.successHandler(successHandler) /* 設置成功處理器 */
.failureHandler(failureHandler) /* 設置失敗處理器*/
.and()
.logout() //登出
.logoutSuccessUrl("/home"); //設置退出頁面
}