最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Security基本原理詳解

 更新時間:2023年05月06日 09:52:37   作者:愛上口袋的天空  
這篇文章主要介紹了Spring Security基本原理詳解,springsecurity底層實現(xiàn)為一條過濾器鏈,就是用戶請求進來,判斷有沒有請求的權(quán)限,拋出異常,重定向跳轉(zhuǎn),需要的朋友可以參考下

1、SpringSecurity 本質(zhì)是一個過濾器鏈

SpringSecurity 采用的是責任鏈的設計模式,它有一條很長的過濾器鏈。現(xiàn)在對這條過濾器鏈的各個進行說明:

  1. WebAsyncManagerIntegrationFilter:將 Security 上下文與 Spring Web 中用于處理異步請求映射的 WebAsyncManager 進行集成。
  2. SecurityContextPersistenceFilter:在每次請求處理之前將該請求相關的安全上下文信息加載到 SecurityContextHolder 中,然后在該次請求處理完成之后,將 SecurityContextHolder 中關于這次請求的信息存儲到一個“倉儲”中,然后將 SecurityContextHolder 中的信息清除,例如在Session中維護一個用戶的安全信息就是這個過濾器處理的。
  3. HeaderWriterFilter:用于將頭信息加入響應中。
  4. CsrfFilter:用于處理跨站請求偽造
  5. LogoutFilter:用于處理退出登錄。
  6. UsernamePasswordAuthenticationFilter:用于處理基于表單的登錄請求,從表單中獲取用戶名和密碼。默認情況下處理來自 /login 的請求。從表單中獲取用戶名和密碼時,默認使用的表單 name 值為 username 和 password,這兩個值可以通過設置這個過濾器的usernameParameter 和 passwordParameter 兩個參數(shù)的值進行修改。
  7. DefaultLoginPageGeneratingFilter:如果沒有配置登錄頁面,那系統(tǒng)初始化時就會配置這個過濾器,并且用于在需要進行登錄時生成一個登錄表單頁面。
  8. BasicAuthenticationFilter:檢測和處理 http basic 認證。
  9. RequestCacheAwareFilter:用來處理請求的緩存。
  10. SecurityContextHolderAwareRequestFilter:主要是包裝請求對象request。
  11. AnonymousAuthenticationFilter:檢測 SecurityContextHolder 中是否存在 Authentication 對象,如果不存在為其提供一個匿名 Authentication。
  12. SessionManagementFilter:管理 session 的過濾器
  13. ExceptionTranslationFilter:處理 AccessDeniedException 和 AuthenticationException 異常。
  14. FilterSecurityInterceptor:可以看做過濾器鏈的出口。
  15. RememberMeAuthenticationFilter:當用戶沒有登錄而直接訪問資源時, 從 cookie 里找出用戶的信息, 如果 Spring Security 能夠識別出用戶提供的remember me cookie, 用戶將不必填寫用戶名和密碼, 而是直接登錄進入系統(tǒng),該過濾器默認不開啟。

2、SpringSecurity 流程圖

先來看下面一個 Spring Security 執(zhí)行流程圖,只要把 SpringSecurity 的執(zhí)行過程弄明白了,這個框架就會變得很簡單:

流程說明

  1. 客戶端發(fā)起一個請求,進入 Security 過濾器鏈。
  2. 當?shù)?LogoutFilter 的時候判斷是否是登出路徑,如果是登出路徑則到 logoutHandler ,如果登出成功則到 logoutSuccessHandler 登出成功處理,如果登出失敗則由 ExceptionTranslationFilter ;如果不是登出路徑則直接進入下一個過濾器。
  3. 當?shù)?UsernamePasswordAuthenticationFilter 的時候判斷是否為登錄路徑,如果是,則進入該過濾器進行登錄操作,如果登錄失敗則到 AuthenticationFailureHandler 登錄失敗處理器處理,如果登錄成功則到 AuthenticationSuccessHandler 登錄成功處理器處理,如果不是登錄請求則不進入該過濾器。
  4. 當?shù)?FilterSecurityInterceptor 的時候會拿到 uri ,根據(jù) uri 去找對應的鑒權(quán)管理器,鑒權(quán)管理器做鑒權(quán)工作,鑒權(quán)成功則到 Controller 層否則到 AccessDeniedHandler 鑒權(quán)失敗處理器處理。

3、Security 配置

在 WebSecurityConfigurerAdapter 這個類里面可以完成上述流程圖的所有配置

配置類偽代碼

@Configuration	
@EnableWebSecurity	
public class SecurityConfig extends WebSecurityConfigurerAdapter {	
    @Override	
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {	
        auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());	
    }	
    @Override	
    public void configure(WebSecurity web) throws Exception {	
        web.ignoring().antMatchers("/resources/**/*.html", "/resources/**/*.js");	
    }	
    @Override	
    protected void configure(HttpSecurity http) throws Exception {	
       http	
       .formLogin()	
       .loginPage("/login_page")	
       .passwordParameter("username")	
       .passwordParameter("password")	
       .loginProcessingUrl("/sign_in")	
       .permitAll()	
       .and().authorizeRequests().antMatchers("/test").hasRole("test")	
       .anyRequest().authenticated().accessDecisionManager(accessDecisionManager())	
       .and().logout().logoutSuccessHandler(new MyLogoutSuccessHandler())	
       .and().csrf().disable();	
       http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);	
       http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());	
       http.addFilterAfter(new MyFittler(), LogoutFilter.class);	
    }	
}

配置簡介

  • configure(AuthenticationManagerBuilder auth)

AuthenticationManager 的建造器,配置 AuthenticationManagerBuilder 會讓Security 自動構(gòu)建一個 AuthenticationManager(該類的功能參考流程圖);如果想要使用該功能你需要配置一個 UserDetailService 和 PasswordEncoder。UserDetailsService 用于在認證器中根據(jù)用戶傳過來的用戶名查找一個用戶, PasswordEncoder 用于密碼的加密與比對,我們存儲用戶密碼的時候用PasswordEncoder.encode() 加密存儲,在認證器里會調(diào)用 PasswordEncoder.matches() 方法進行密碼比對。如果重寫了該方法,Security 會啟用 DaoAuthenticationProvider 這個認證器,該認證就是先調(diào)用 UserDetailsService.loadUserByUsername 然后使用 PasswordEncoder.matches() 進行密碼比對,如果認證成功成功則返回一個 Authentication 對象。

  • configure(WebSecurity web)

這個配置方法用于配置靜態(tài)資源的處理方式,可使用 Ant 匹配規(guī)則。

  • configure(HttpSecurity http)

這個配置方法是最關鍵的方法,也是最復雜的方法。我們慢慢掰開來說:

http	
.formLogin()	
.loginPage("/login_page")	
.passwordParameter("username")	
.passwordParameter("password")	
.loginProcessingUrl("/sign_in")	
.permitAll()

這是配置登錄相關的操作從方法名可知,配置了登錄頁請求路徑,密碼屬性名,用戶名屬性名,和登錄請求路徑,permitAll()代表任意用戶可訪問。

http	
.authorizeRequests()	
.antMatchers("/test").hasRole("test")	
.anyRequest().authenticated()	
.accessDecisionManager(accessDecisionManager());

以上配置是權(quán)限相關的配置,配置了一個 /test url 該有什么權(quán)限才能訪問, anyRequest() 表示所有請求,authenticated() 表示已登錄用戶才能訪問, accessDecisionManager() 表示綁定在 url 上的鑒權(quán)管理器

為了對比,現(xiàn)在貼出另一個權(quán)限配置清單:

http.authorizeRequests()	
.antMatchers("/tets_a/**","/test_b/**").hasRole("test")	
.antMatchers("/a/**","/b/**").authenticated()	
.accessDecisionManager(accessDecisionManager())

我們可以看到權(quán)限配置的自由度很高,鑒權(quán)管理器可以綁定到任意 url 上;而且可以硬編碼各種 url 權(quán)限:

http	
.logout()	
.logoutUrl("/logout")	
.logoutSuccessHandler(new MyLogoutSuccessHandler())

登出相關配置,這里配置了登出 url 和登出成功處理器:

http	
.exceptionHandling()	
.accessDeniedHandler(new MyAccessDeniedHandler());

上面代碼是配置鑒權(quán)失敗的處理器。

http.addFilterAfter(new MyFittler(), LogoutFilter.class);	
http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

上面代碼展示如何在過濾器鏈中插入自己的過濾器,addFilterBefore 加在對應的過濾器之前,addFilterAfter 加在對應的過濾器之后,addFilterAt 加在過濾器同一位置,事實上框架原有的 Filter 在啟動 HttpSecurity 配置的過程中,都由框架完成了其一定程度上固定的配置,是不允許更改替換的。根據(jù)測試結(jié)果來看,調(diào)用 addFilterAt 方法插入的 Filter ,會在這個位置上的原有 Filter 之前執(zhí)行。

注:關于 HttpSecurity 使用的是鏈式編程,其中 http.xxxx.and.yyyyy 這種寫法和 http.xxxx;http.yyyy 寫法意義一樣。

  • 自定義 AuthenticationManager 和 AccessDecisionManager

重寫 authenticationManagerBean() 方法,并構(gòu)造一個 authenticationManager:

@Override	
public AuthenticationManager authenticationManagerBean() throws Exception {	
    ProviderManager authenticationManager = new ProviderManager(Arrays.asLis(getMyAuthenticationProvider(),daoAuthenticationProvider()));	
    return authenticationManager;	
}

我這里給 authenticationManager 配置了兩個認證器,執(zhí)行過程參考流程圖。

定義構(gòu)造AccessDecisionManager的方法并在配置類中調(diào)用,配置參考 configure(HttpSecurity http) 說明:

public AccessDecisionManager accessDecisionManager(){	
    List<AccessDecisionVoter<? extends Object>> decisionVoters	
            = Arrays.asList(	
            new MyExpressionVoter(),	
            new WebExpressionVoter(),	
            new RoleVoter(),	
            new AuthenticatedVoter());	
    return new UnanimousBased(decisionVoters);	
}

投票管理器會收集投票器投票結(jié)果做統(tǒng)計,最終結(jié)果大于等于0代表通過;每個投票器會返回三個結(jié)果:-1(反對),0(通過),1(贊成)。

4、Security 權(quán)限系統(tǒng)

  • UserDetails

Security 中的用戶接口,我們自定義用戶類要實現(xiàn)該接口。

  • GrantedAuthority

Security 中的用戶權(quán)限接口,自定義權(quán)限需要實現(xiàn)該接口:

public class MyGrantedAuthority implements GrantedAuthority {	
    private String authority;	
}

authority 表示權(quán)限字段,需要注意的是在 config 中配置的權(quán)限會被加上 ROLE_ 前綴,比如我們的配置 authorizeRequests().antMatchers("/test").hasRole("test"),配置了一個 test 權(quán)限但我們存儲的權(quán)限字段(authority)應該是 ROLE_test 。

  • UserDetailsService

Security 中的用戶 Service,自定義用戶服務類需要實現(xiàn)該接口:

@Service	
public class MyUserDetailService implements UserDetailsService {	
    @Override	
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {	
      return.....	
    }	
}

loadUserByUsername的作用在上文中已經(jīng)說明,就是根據(jù)用戶名查詢用戶對象。

  • SecurityContextHolder

用戶在完成登錄后 Security 會將用戶信息存儲到這個類中,之后其他流程需要得到用戶信息時都是從這個類中獲得,用戶信息被封裝成 SecurityContext ,而實際存儲的類是 SecurityContextHolderStrategy ,默認的SecurityContextHolderStrategy 實現(xiàn)類是 ThreadLocalSecurityContextHolderStrategy 它使用了ThreadLocal來存儲了用戶信息。

手動填充 SecurityContextHolder 示例:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("test","test",list);	
SecurityContextHolder.getContext().setAuthentication(token);

對于使用 token 鑒權(quán)的系統(tǒng),我們就可以驗證token后手動填充SecurityContextHolder,填充時機只要在執(zhí)行投票器之前即可,或者干脆可以在投票器中填充,然后在登出操作中清空SecurityContextHolder。

5、Security 擴展

Security 可擴展的有

  1. 鑒權(quán)失敗處理器
  2. 驗證器
  3. 登錄成功處理器
  4. 投票器
  5. 自定義token處理過濾器
  6. 登出成功處理器
  7. 登錄失敗處理器
  8. 自定義 UsernamePasswordAuthenticationFilter
  • 鑒權(quán)失敗處理器

Security 鑒權(quán)失敗默認跳轉(zhuǎn)登錄頁面,我們可以實現(xiàn) AccessDeniedHandler 接口,重寫 handle() 方法來自定義處理邏輯;然后參考配置類說明將處理器加入到配置當中。

  • 驗證器

實現(xiàn) AuthenticationProvider 接口來實現(xiàn)自己驗證邏輯。需要注意的是在這個類里面就算你拋出異常,也不會中斷驗證流程,而是算你驗證失敗,我們由流程圖知道,只要有一個驗證器驗證成功,就算驗證成功,所以你需要留意這一點。

  • 登錄成功處理器

在 Security 中驗證成功默認跳轉(zhuǎn)到上一次請求頁面或者路徑為 "/" 的頁面,我們同樣可以自定義:繼承 SimpleUrlAuthenticationSuccessHandler 這個類或者實現(xiàn) AuthenticationSuccessHandler 接口。我這里建議采用繼承的方式,SimpleUrlAuthenticationSuccessHandler 是默認的處理器,采用繼承可以契合里氏替換原則,提高代碼的復用性和避免不必要的錯誤。

  • 投票器

投票器可繼承 WebExpressionVoter 或者實現(xiàn) AccessDecisionVoter接口;WebExpressionVoter 是 Security 默認的投票器;我這里同樣建議采用繼承的方式;添加到配置的方式參考 上文;

注意:投票器 vote 方法返回一個int值;-1代表反對,0代表棄權(quán),1代表贊成;投票管理器收集投票結(jié)果,如果最終結(jié)果大于等于0則放行該請求。

  • 自定義token處理過濾器

自定義 token 處理器繼承自 OncePerRequestFilter 或者 GenericFilterBean 或者 Filter 都可以,在這個處理器里面需要完成的邏輯是:獲取請求里的 token,驗證 token 是否合法然后填充 SecurityContextHolder ,雖然說過濾器只要添加在投票器之前就可以,但我這里還是建議添加在 http.addFilterAfter(new MyFittler(), LogoutFilter.class);

  • 登出成功處理器

實現(xiàn)LogoutSuccessHandler接口,添加到配置的方式參考上文。

  • 登錄失敗處理器

登錄失敗默認跳轉(zhuǎn)到登錄頁,我們同樣可以自定義。繼承 SimpleUrlAuthenticationFailureHandler 或者實現(xiàn) AuthenticationFailureHandler,建議采用繼承。

  • 自定義UsernamePasswordAuthenticationFilter

我們自定義UsernamePasswordAuthenticationFilter可以極大提高我們 Security的靈活性(比如添加驗證驗證碼是否正確的功能)。

我們直接繼承 UsernamePasswordAuthenticationFilter ,然后在配置類中初始化這個過濾器,給這個過濾器添加登錄失敗處理器,登錄成功處理器,登錄管理器,登錄請求 url 。

這里配置略微復雜,貼一下代碼清單

初始化過濾器:

MyUsernamePasswordAuthenticationFilte getAuthenticationFilter(){	
    MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new MyUsernamePasswordAuthenticationFilter(redisService);	
    myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(new MyUrlAuthenticationFailureHandler());	
    myUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());	
    myUsernamePasswordAuthenticationFilter.setFilterProcessesUrl("/sign_in");	
    myUsernamePasswordAuthenticationFilter.setAuthenticationManager(getAuthenticationManager());	
    return myUsernamePasswordAuthenticationFilter;	
}

添加到配置:

http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

 6、總結(jié)

對于 Security 的擴展配置關鍵在于 configure(HttpSecurityhttp) 方法;擴展認證方式可以自定義 authenticationManager 并加入自己驗證器,在驗證器中拋出異常不會終止驗證流程;擴展鑒權(quán)方式可以自定義 accessDecisionManager 然后添加自己的投票器并綁定到對應的 url(url 匹配方式為 ant)上,投票器 vote(Authenticationauthentication,FilterInvocationfi,Collection<ConfigAttribute>attributes) 方法返回值為三種:-1 0 1,分別表示反對棄權(quán)贊成。

對于 token 認證的校驗方式,可以暴露一個獲取的接口,或者重寫 UsernamePasswordAuthenticationFilter 過濾器和擴展登錄成功處理器來獲取 token,然后在 LogoutFilter 之后添加一個自定義過濾器,用于校驗和填充 SecurityContextHolder。

另外,Security 的處理器大部分都是重定向的,我們的項目如果是前后端分離的話,我們希望無論什么情況都返回 json ,那么就需要重寫各個處理器了。

到此這篇關于Spring Security基本原理詳解的文章就介紹到這了,更多相關Spring Security原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • StreamAPI多次消費一個stream代碼實例

    StreamAPI多次消費一個stream代碼實例

    這篇文章主要介紹了StreamAPI多次消費一個stream代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • 淺談java日志格式化

    淺談java日志格式化

    不管我們使用何種語言開發(fā),一旦程序發(fā)生異常,日志是一個很重要的數(shù)據(jù)。但是并不是意味著打印的日志越多越好,我們需要的是有用的日志。下面小編來和大家一起學習以下知識
    2019-05-05
  • SpringBoot數(shù)據(jù)庫恢復的兩種方法mysqldump和mysqlbinlog

    SpringBoot數(shù)據(jù)庫恢復的兩種方法mysqldump和mysqlbinlog

    binlog用來實現(xiàn)主從復制,也常用來誤刪數(shù)據(jù)庫找回丟失的記錄,本文主要介紹了SpringBoot數(shù)據(jù)庫恢復的兩種方法mysqldump和mysqlbinlog,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Mybatis-Plus中的查詢指定字段

    Mybatis-Plus中的查詢指定字段

    在使用Mybatis-Plus進行數(shù)據(jù)查詢時,可以通過指定字段來優(yōu)化查詢效率,方法一和方法二分別執(zhí)行不同的SQL語句,其中方法二在執(zhí)行時通常會更高效,因為它可能通過減少數(shù)據(jù)處理量和優(yōu)化查詢結(jié)構(gòu)來提升性能,比較兩種方法的SQL執(zhí)行情況
    2024-09-09
  • Tomcat內(nèi)存溢出分析及解決方法

    Tomcat內(nèi)存溢出分析及解決方法

    堆是給開發(fā)人員用的上面說的就是,是在JVM啟動時創(chuàng)建;非堆是留給JVM自己用的,用來存放類的信息的,本文將詳細介紹Tomcat內(nèi)存溢出,需要了解更多的朋友可以參考下
    2012-11-11
  • JDK1.8中的ConcurrentHashMap源碼分析

    JDK1.8中的ConcurrentHashMap源碼分析

    這篇文章主要介紹了JDK1.8中的ConcurrentHashMap源碼分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Springboot內(nèi)置Tomcat配置參數(shù)調(diào)優(yōu)方式

    Springboot內(nèi)置Tomcat配置參數(shù)調(diào)優(yōu)方式

    這篇文章主要介紹了Springboot內(nèi)置Tomcat配置參數(shù)調(diào)優(yōu)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • java通過Arrays.sort(int[] a)實現(xiàn)由大到小排序的方法實現(xiàn)

    java通過Arrays.sort(int[] a)實現(xiàn)由大到小排序的方法實現(xiàn)

    Java中的Arrays.sort()方法是一種內(nèi)置的排序方法,用于對數(shù)組進行排序,本文就來介紹一下java中的Arrays.sort()排序方法的用法,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • 詳解Java中的File文件類以及FileDescriptor文件描述類

    詳解Java中的File文件類以及FileDescriptor文件描述類

    在Java中File類可以用來新建文件和目錄對象,而FileDescriptor類則被用來表示文件或目錄的可操作性,接下來我們就來詳解Java中的File文件類以及FileDescriptor文件描述類
    2016-06-06
  • 詳解SpringMVC組件之HandlerMapping(二)

    詳解SpringMVC組件之HandlerMapping(二)

    這篇文章主要介紹了詳解SpringMVC組件之HandlerMapping(二),HandlerMapping組件是Spring?MVC核心組件,用來根據(jù)請求的request查找對應的Handler,在Spring?MVC中,有各式各樣的Web請求,每個請求都需要一個對應的Handler來處理,需要的朋友可以參考下
    2023-08-08

最新評論

铁岭县| 上饶县| 临沧市| 靖西县| 来凤县| 铅山县| 凤台县| 惠水县| 新和县| 麟游县| 华容县| 赫章县| 靖江市| 九江市| 梅州市| 镇康县| 文成县| 佛山市| 湖州市| 玛沁县| 潢川县| 怀宁县| 濮阳市| 青州市| 东宁县| 炉霍县| 肥乡县| 汨罗市| 莆田市| 英德市| 江口县| 军事| 调兵山市| 吉木乃县| 马龙县| 佛冈县| 伊金霍洛旗| 延寿县| 无锡市| 湖州市| 腾冲县|