SpringSecurity
SpringSecurity是Spring大家族中解決認證授權問題的框架。
大家針對安全問題之前採用基於Session認證的方式,太過於繁瑣,而且硬編碼太嚴重,Security不僅可以做到Session所能實現的功能,而且依賴於Spring的Aop可以在不修改原有代碼的前提下,提供安全保護。
接下來我用最簡單的配置爲我們的web應用配置SpringSecurity,配置完成後,體驗之後,我再進行細節的說明。
首先導入依賴
前提是當前項目已經是web項目,並且有spring的相關依賴,再加入下面依賴即可,如果是sprigboot只需加入security的stater即可
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring‐security‐web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring‐security‐config</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
之後對Security進行最簡單的配置
//這個類實現了WebApplication接口,會自動被spring發現,並在web容器中註冊DelegatingFilterProxy,這個代理類會是一個filter但他本身不會做什麼,而是
//交給spring容器中的spirngSecurityFilterChain進行處理,你也可以大概理解這個代理連接起了Spring 與SpringSecurity,即使他看起來沒什麼特色
public class SecurityInit extends AbstractSecurityWebApplicationInitializer {
}
@Configuration
@EnableWebSecurity//啓用spring對security的支持,其實也就是註冊上面所說的springSecurityFilterChain
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()//表示啓用http保護
.anyRequest().authenticated()//對所有請求需要認證
.and()
.formlogin();//表示允許用表單登錄
}
}
進行過上面的配置,你只要重啓應用,就會發現你被自動跳轉到Security自動爲你生成的登錄頁面(如果你發送/logout會發現也爲你自動生成了退出登錄功能),當然因爲Security的版本不同這個頁面會有所不同,但這不是你所真正關心的對吧。
但是很顯然你根本沒有寫過一點關於賬號密碼的配置,
這個頁面無法登陸進去,進下來我們進行賬號密碼的配置,我們需要在WebSecurityConfig中重寫config(AuthentticationManagerBuilder auth)進行配置。
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("123").password("123").role("STUDENT");
}
這樣我們就創建了一個賬號密碼都爲123,擁有sutdent權限的用戶,這樣起碼我們就能登陸了
但是你不覺得把所有請求都進行攔截有點嚴格了嗎,
畢竟我們頁面中的某些頁面,
我們並不希望進行攔截,即使未認證我也能讓用戶看到,
所以我們可以進行更 細粒度的配置安全策略
我們更改一下剛纔的配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/h").authenticated()//這個參數是字符串數組,你可以傳入多個,你也可以繼續.antMatcher進行配置
.and()
.formLogin();
}
這樣我們就只對"/h"請求進行安全認證,其他的請求就會被放行,到這裏我想你感覺到了,面向切面編程的好處,但現在爲止我們沒有修改原來web應用的代碼,
只是加了一些關於安全認證的配置,感謝Spring的AOP吧!
,這些認證配置差不多滿足你的需求,當然還有更多可能的實現,
比如限制用於的IP,限制請求的方式,甚至是使用SPEL表達式滿足你的花裏胡哨的需求,
我現在不會細說這些,如果你想更加深入瞭解,可以評論,如果有必要我會寫。
你可能在想我的數據庫的那麼多用戶,我總不能一個一個寫上去吧,而且我的密碼可能是加密過的,下面我們來解決一下這個問題
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
通過上面的這個配置其實就可以了,security自動會去我們去我們的數據查用戶密碼,
但是對我們的數據庫表就有一些要求,如果有興趣可以去查或者聯繫我,
接下來我會介紹一種更加通用的方式來和你的數據庫交流,
你只需要聲明一個bean如下
@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
StudentMapper studentMapper;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Student student=studentMapper.findStudentByName(userName);
//這個User是Security提供的一個UserDetail的實現,我們可以直接用
return new User(student.getName(),student.getPassword(),"STUDENT");
}
}
通過上面的代碼,當用戶進行表單登錄時,Security會幫我們拿着用戶所提交的表單中的userName,調用USerDetailService實現類,
也就是我們剛剛寫的這個類,來進行認證,通過這個類的loadUserByUsername方法,傳入用戶所提交的用戶名,來查找數據庫,
其實security並不關心我們這個方法的方法體是什麼,他只關心我們最後返回的這個UserDetail的實現,也就是我們這裏最後返回的User,
這是Security爲我們提供的UserDetail的實現,Security會用我們最後返回的這個User裏面的密碼和用戶表單提交的數據中的密碼進行對比,
如果一樣就會認爲認證通過。
最後說一下密碼加密問題
因爲我們的數據庫很多時候放的是加密後的密碼,
那麼認證的時候UserDetail中的密碼就是加密後的,
我們任何時候都不會去解密我們的密碼,
所以我們可以將表單提交過來的密碼進行加密然後再和數據庫進行對比就可以了
我們直接聲明一個加密器bean,security就自動會使用這個加密器對錶單數據中的密碼進行
加密後再和UserDetail進行對比
//如果你的數據庫密碼是使用BCryot算法加密
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
我想你肯定感受到AOP技術的強大,我們應用似乎都不知道自己以及被保護了起來,
不過也是應用本身並不需要關心安全,它只需要做好自己的業務邏輯,
這也就是面向切面編程的優點