最近實在比較忙,很難抽出時間來繼續更 Spring Security 實戰乾貨系列。今天正好項目中 Spring Security 須要對認證受權異常的處理,就分享出來吧 。html
Spring Security 中的異常主要分爲兩大類:一類是認證異常,另外一類是受權相關的異常。java
AuthenticationException
是在用戶認證的時候出現錯誤時拋出的異常。主要的子類如圖:web
根據該圖的信息,系統用戶不存在,被鎖定,憑證失效,密碼錯誤等認證過程當中出現的異常都由 AuthenticationException
處理。spring
AccessDeniedException
主要是在用戶在訪問受保護資源時被拒絕而拋出的異常。同 AuthenticationException
同樣它也提供了一些具體的子類。以下圖:json
AccessDeniedException
的子類比較少,主要是 CSRF
相關的異常和受權服務異常。瀏覽器
Http 協議對認證受權的響應結果也有規定。服務器
HTTP 401 錯誤 - 未受權(Unauthorized) 通常來講該錯誤消息代表您首先須要登陸(輸入有效的用戶名和密碼)。 若是你剛剛輸入這些信息,馬上就看到一個 401
錯誤,就意味着,不管出於何種緣由您的用戶名和密碼其中之一或二者都無效(輸入有誤,用戶名暫時停用,帳戶被鎖定,憑證失效等) 。總之就是認證失敗了。其實正好對應咱們上面的 AuthenticationException
。微信
HTTP 403 錯誤 - 被禁止(Forbidden) 出現該錯誤代表您在訪問受限資源時沒有獲得許可。服務器理解了本次請求可是拒絕執行該任務,該請求不應重發給服務器。而且服務器想讓客戶端知道爲何沒有權限訪問特定的資源,服務器應該在返回的信息中描述拒絕的理由。通常實踐中咱們會比較模糊的代表緣由。 該錯誤對應了咱們上面的 AccessDeniedException
。app
咱們在 Spring Security 實戰乾貨系列文章中的 自定義配置類入口 WebSecurityConfigurerAdapter 一文中提到 HttpSecurity
提供的 exceptionHandling()
方法用來提供異常處理。該方法構造出 ExceptionHandlingConfigurer
異常處理配置類。該配置類提供了兩個實用接口:ide
AuthenticationException
異常 AccessDeniedException
異常 咱們只要實現並配置這兩個異常處理類便可實現對 Spring Security 認證受權相關的異常進行統一的自定義處理。
以 json
信息響應。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
/**
* @author dax
* @since 2019/11/6 22:11
*/
public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//todo your business
HashMap<String, String> map = new HashMap<>(2);
map.put("uri", request.getRequestURI());
map.put("msg", "認證失敗");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
ObjectMapper objectMapper = new ObjectMapper();
String resBody = objectMapper.writeValueAsString(map);
PrintWriter printWriter = response.getWriter();
printWriter.print(resBody);
printWriter.flush();
printWriter.close();
}
}複製代碼
一樣以 json
信息響應。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
/**
* @author dax
* @since 2019/11/6 22:19
*/
public class SimpleAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//todo your business
HashMap<String, String> map = new HashMap<>(2);
map.put("uri", request.getRequestURI());
map.put("msg", "認證失敗");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
ObjectMapper objectMapper = new ObjectMapper();
String resBody = objectMapper.writeValueAsString(map);
PrintWriter printWriter = response.getWriter();
printWriter.print(resBody);
printWriter.flush();
printWriter.close();
}
}複製代碼
其實我我的建議 Http 狀態碼 都返回 200
而將 401 狀態在 元信息 Map
中返回。由於異常狀態碼在瀏覽器端會以 error 顯示。咱們只要能捕捉到 401
和 403
就能認定是認證問題仍是受權問題。
實現了上述兩個接口後,咱們只須要在 WebSecurityConfigurerAdapter
的 configure(HttpSecurity http)
方法中配置便可。相關的配置片斷以下:
http.exceptionHandling().accessDeniedHandler(new SimpleAccessDeniedHandler()).authenticationEntryPoint(new SimpleAuthenticationEntryPoint())複製代碼
今天咱們對 Spring Security 中的異常處理進行了講解。分別實現了自定義的認證異常處理和自定義的受權異常處理。相關的 DEMO 可關注微信公衆號: Felordcn 回覆 ss07 獲取。
關注公衆號:Felordcn獲取更多資訊