創建項目
創建一個Springboot web項目,並寫一個簡單的hello控制器,其行爲只需要簡單返回一個響應即可,例如:
@RestController
public class HelloController {
@RequestMapping("/hello")
public JsonResult hello() {
return JsonResult.OK();
}
}
運行它,請求 /hello,會返回響應,注意此時沒有任何權限機制對請求進行限制,也就是任何人都可以訪問/hello資源。
引入依賴
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
<version>
2.6.7
</version>
</dependency>
默認加載
在引入Security後如果不做改動,Spring框架會在運行時自動加載Security並運行默認機制,效果就是Security會將整個項目請求保護起來。重新運行應用並訪問/hello,瀏覽器不再直接返回響應,而是跳轉到/login並顯示一個默認的登錄頁面,Security起作用了!
發生了什麼
Spring會自動加載Security默認安全機制,在請求發生後和Servlet處理請求前使用各種Filter處理這次請求,其中就包括Security框架所包含的Filter。下面代碼告訴了我們默認機制發生了什麼
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnDefaultWebSecurity
static class SecurityFilterChainConfiguration {
SecurityFilterChainConfiguration() {
}
@Bean
@Order(2147483642)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
http.formLogin();
http.httpBasic();
return (SecurityFilterChain)http.build();
}
}
http的請求要開啓權限保護(authorizaRequests()),哪些請求要保護?任何請求(anyRequest()),這些請求都要是已認證的(authenticated),通過什麼方式認證,通過表單認證(formLogin())或Basic認證(httpBasic())——這是我基於教程的理解
註解@ConditionalOnDefaultWebSecurity
是對defaultSecurityFilterChain
方法在什麼條件下生效的聲明,進入註解看到
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({DefaultWebSecurityCondition.class})
public @interface ConditionalOnDefaultWebSecurity {
}
@Conditional
註解說明ConditionalOnDefaultWebSecurity
的使用條件是DefaultWebSecurityCondition
,再進入DefaultWebSecurityCondition
查看一下
class DefaultWebSecurityCondition extends AllNestedConditions {
DefaultWebSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnMissingBean({WebSecurityConfigurerAdapter.class, SecurityFilterChain.class})
static class Beans {
Beans() {
}
}
@ConditionalOnClass({SecurityFilterChain.class, HttpSecurity.class})
static class Classes {
Classes() {
}
}
}
DefaultWebSecurityCondition
在兩種條件下生效,在當前類路徑中存在某些類定義的時候(@ConditionalOnClass)SecurityFilterChain.class
或HttpSecurity.class
的時候,和(在現有工廠中)當不存在某些Bean的實例時候(@ConditionalOnMissingBean)不存在WebSecurityConfigurerAdapter.class
或SecurityFilterChain.class
的時候。在引入依賴後,並沒有自己定義WebSecurityConfigurerAdapter
和SecurityFilterChain
,因此剛纔的過濾鏈滿足了條件,起了作用,產生了效果。
總結一下,Security默認使用了defaultSecurityFilterChain
(中的配置)進行安全行爲,如果希望改變默認行爲,需要自行定義WebSecurityConfigurerAdapter
或SecurityFilterChain
。定義的方法是創建自己的類繼承並註解,使具體實現類在Spring容器中生效。Spring Security 推薦覆蓋WebSecurityConfigurerAdapter
。
bilibili - 編程不良人 - SpringSecurity最新實戰