Hi 大家好 今天我將和大家分享一下我在做安全框架遇到的難題以及如果正確使用spring security以及Spring Security OAuth2 Client 。
本文將講述一下幾點:
1 為什么需要Spring Security?
2 如何將 Spring Security與Spring Boot結合?
3 如何使用Spring Security進行認證,授權流程的登錄驗證?
1 因為Spirng Security 可以解決Session 固化問題,如果沒有安全框架,會有cookie攻擊的問題,黑客很容易就可以拿到一個用戶的sessionId(默認是一個名為JSSIONID的cookie的值即為sessionId),然后偽裝登錄。僅僅通過配置就可以打開唯一登錄功能(shiro沒有唯一登錄的機制,我以前是自己開發(fā),結合攔截器 以及 redis實現(xiàn)了唯一登錄功能),還有csrf機制(后續(xù)和大家分享csrf)。
2 Spring Boot的眾多好處中的一個好處就是用java config代替 xml的配置,這樣無疑性能會更高一些。然而大家第一次接觸java config,會很陌生。其實java config很簡單的,從表面上看就是將xml的標簽用@Bean注解代替。Spring Boot 有更多的注解解決程序問題,例如@EnableAsync和@Async注解,能實現(xiàn)方法的異步。等等(如果大家有興趣,后續(xù)會和大家分享Spring Boot)。
官網(wǎng)有相關的demo項目,可以看到Spring Security與Spring Boot的結合。
https://spring.io/guides/tutorials/spring-security-and-angular-js/
然而官網(wǎng)的demo項目,僅僅是演示了Spring Security框架可以解決什么企業(yè)問題:如 安全登錄,權限控制,然而并不能拿到企業(yè)當中來用。接下來,我將和大家分享最關鍵也是最核心的內(nèi)容就是Spring Security如何在企業(yè)當中解決安全認證(我使用了md5加密來作為密碼加密器),權限控制。
3 首先是jar包依賴,我使用的是maven項目,需要添加maven依賴:
org.springframework.bootspring-boot-starter-security
下面仔細說明一下Spring Security工作的核心類信息:
HttpSecurity類:進行權限的配置,具體哪里路徑可以直接放行.antMatchers(...).permitAll()哪些路徑需要權限認證 .antMatchers(...).hasAutority(...)? 僅測試需要.anyRequest().authenticated()配置登錄頁面,登錄錯誤頁面 以及安全退出,安全退出頁面,記住我等等。
FilterInvocationSecurityMetadataSource:該類為過濾器類,容器啟動就會加載該類進行資源 角色的加載。需要自定義該類的實現(xiàn)類,自定義init方法,從數(shù)據(jù)庫加載該程序需要的全部的權限信息。然后每次請求都回走getAttributes,加載該url需要的角色列表。AccessDecisionManager:該接口 的decide方法即為權限審核接口,判斷當前用戶有沒有訪問該url的權限
UserDetailsService: 用戶登錄真正工作類,需要自定義實現(xiàn)類實現(xiàn)該接口,實現(xiàn)loadUserByUserNameUserDetails:用戶信息實體類接口,自定義的javaBean需要實現(xiàn)該類。下面是我的部分的java config代碼,供大家參考。
```@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception?
{http.antMatcher("/**").authorizeRequests().antMatchers( "/se-home","/se-public/**","/login**", "/webjars/**","/js/**","/myexcel","/upload*").permitAll().antMatchers("/se/**").hasAuthority("ROLE_USER").anyRequest().fullyAuthenticated().and().formLogin().loginPage("/se-goLogin").failureUrl("/se-goLogin?error").loginProcessingUrl("/se-login").defaultSuccessUrl("/se/se-hello").permitAll().and().logout().logoutSuccessUrl("/se-home").permitAll().invalidateHttpSession(true).and().rememberMe();}@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(getCustomUserDetailsServiceImpl())//自定義開發(fā)的UserDeatilsService.passwordEncoder(getMD5Encoder());//自定義開發(fā)的密碼加密器}``
`自定義的類都需要通過@Bean注解的形式交給Spring Boot來管理,如下獲取Spring Security的過濾器代理的類配置:``
`@Beanpublic DelegatingFilterProxy getDelegatingFilterProxy(){FilterRegistrationBean registrationBean=new FilterRegistrationBean();DelegatingFilterProxy delegatingFilterProxy=new DelegatingFilterProxy();delegatingFilterProxy.setTargetBeanName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);registrationBean.setFilter(delegatingFilterProxy);registrationBean.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);registrationBean.addUrlPatterns("/*");registrationBean.setOrder(1);return delegatingFilterProxy;}``
`上面的那個bean是有一定難度的配置,我自己琢磨了好久,參考了大量的資料,才琢磨出來。其他的配置相對比較簡單大家可以自己動手,來做,其實在做的過程中,大家的能力就在不知不覺中有了很大的提升。具體的我就不貼了喲,相信大家可以的。
做好了SpirngBoot與Spring Security的整合,接下來就是接著上一篇博客繼續(xù)說明Spring Security 與Spring Boot結合后的使用框架原理流程:
1 容器啟動,spring security 從庫里頭加載權限信息 并以map的形式存?。℉ashMap? resourceMap key:資源url,value:角色名稱 ROLE_為前綴的值)
2 用戶進行登錄操作:加載用戶的角色列表(Collection)loadUserByUsername
3 決策當前用戶有沒有訪問該url的權限decide從兩個集合中找到相互匹配equals的角色名稱,就放行然后就是對相應的需要自定義的開發(fā),只要流程搞明白了 并且知道哪些是需要自定義的開發(fā),接下來的開發(fā)的工作就比較簡單了。
我是用google java style (http://www.hawstein.com/posts/google-java-style.html ) 來規(guī)范了自己的代碼,大家也可以這樣,養(yǎng)成一個良好的開發(fā)習慣,很重要 會避免很多彎路。