1 匯入Spring Security的相關依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2 Spring Security認證方式之Http基本認證
2.1 實現流程
-
Http基本認證是最簡單的認證方式,不需要任何配置,匯入依賴啟動應用後就會彈出預設的httpBasic認證框。也相當於在實現了BrowserSecurityConfig類進行了如下配置:
@Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //HttpBasic的alert框登入 http.httpBasic() .and() .authorizeRequests()//對請求進行授權 .anyRequest()//任何請求 .authenticated(); } }
在Spring Security的預設配置中,使用使用者名稱user,密碼為控制檯列印的隨機碼。
-
可以在resources配置檔案中修改預設的使用者名稱和密碼,指定密碼後控制檯不再生成動態的隨機碼。
- properties配置
-
security.user.name=user security.user.password=123456
- yml配置
-
spring: security: user: name: user password: 123456
2.2 Http基本認證原理
-
客戶端向服務端請求被保護的資源,服務端向客戶端請求使用者名稱和密碼,瀏覽器彈出登入輸入框,HttpBasic模式要求傳輸的使用者名稱密碼使用Base64模式進行加密。客戶端向服務端發起login的請求。
-
客戶端傳送的Http請求中會使用Authorization作為Header,即“Basic + 空格 + Base64密碼”。而Base64很容易被逆向解碼,所以HttpBstic的認證方式是不安全的。
伺服器接收到請求後,到達BasicAuthenticationFilter過濾器,將提取Header值,並使用用於驗證使用者身份的相同演算法Base64進行解碼。解碼結果與登入驗證的使用者名稱密碼匹配,匹配成功則可以繼續過濾器後續的訪問。
2.3 小結
Http認證雖然配置簡單,但是安全性極差,靈活性不高,無法攜帶cookie,所以一般應用會用安全性和靈活性更強的表單認證方式,可以通過自定義登入和驗證邏輯,提高安全性。
3 表單認證
3.1 實現流程
-
配置使用自定義的表單登入
@Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 表單登入,而不是httpBasic http.formLogin() // 自定義登入頁面 .loginPage("login.html") // 指定處理登入請求的路徑 .loginProcessingUrl("/login") // 不限制登入頁面的訪問 .permitAll() .and() .authorizeRequests()//對請求進行授權 .anyRequest()//任何請求 .authenticated() .and() .csrf() .disable(); } }
-
自定義認證成功/失敗的處理邏輯
Spring Security中預設的成功處理邏輯定義在AbstractAuthenticationTargetUrlRequestHandler類中,在傳送登入請求並認證成功後頁面會跳轉回到原來的訪問頁面,頁面跳轉不適用於前後端分離的系統中,因此可以自定義成功後的處理邏輯,登入後返回JSON資料。
實現AuthenticationSuccessHandler和 AuthenticationFailureHandle類中的處理方法。
@Component("customAuthenticationSuccessHandler") public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=UTF-8"); httpServletResponse.getWriter().write(objectMapper.writeValueAsString(authentication)); } }
@Component("customAuthenticationFailureHandler") public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { log.info("登入失敗"); httpServletResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); httpServletResponse.setContentType("application/json;charset=UTF-8"); httpServletResponse.getWriter().write(e.getMessage()); } }
在WebSecurity配置檔案中配置自定義的處理器
@Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 表單登入,而不是httpBasic http.formLogin() // 自定義登入頁面 .loginPage("login.html") // 不限制登入頁面的訪問 .permitAll() // 自定義認證後的處理器 .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .and() .authorizeRequests()//對請求進行授權 .anyRequest()//任何請求 .authenticated() .and() .csrf() .disable(); } }
3.2 關於HttpSecurity
在配置檔案中使用HttpSecurity進行HTTP請求安全策略的配置,HttpSecurity被設計為鏈式呼叫,執行每個方法會返回一個預期的上下文,用於連續呼叫,其中:
-
authorizeRequests()相當於XML中的<intercept-url>標籤,它返回一個URL攔截註冊器,可以呼叫它提供的anyRequest()、antMatchers()、regexMatchers()等方法來匹配系統的URL,併為它指定安全策略。
-
formLogin()相當於XML中的<form-login>標籤,宣告瞭需要Spring Security提供的表單認證方式,返回對應的配置器,loginPage()用於指定自定義的登入頁面。Spring Security會為該登入頁註冊一個POST路由用於接收登入請求。
-
httpBasic()相當於XML中的<http-basic>標籤
-
csrf()相當於XML中的<csrf>標籤,提供了跨站請求偽造防護功能,繼承WebSecurityConfigurerAdapter會預設開啟csrf()方法。
使用and()方法可以結束當前標籤,上下文會回到HttpSecurity,否則鏈式呼叫的上下文會自動進入對應的標籤域。