91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Security資源放行策略有哪些

發布時間:2021-12-17 13:59:17 來源:億速云 閱讀:187 作者:iii 欄目:開發技術

本篇內容主要講解“Spring Security資源放行策略有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring Security資源放行策略有哪些”吧!

Spring Security 中,到底該怎么樣給資源額外放行?

1.兩種思路

在 Spring Security 中,有一個資源,如果你希望用戶不用登錄就能訪問,那么一般來說,你有兩種配置策略:

第一種就是在 configure(WebSecurity web) 方法中配置放行,像下面這樣:

@Override
public void configure(WebSecurity web) throws Exception {
   web.ignoring().antMatchers("/css/**", "/js/**", "/index.html", "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode");
}

第二種方式是在 configure(HttpSecurity http) 方法中進行配置:

http.authorizeRequests()
       .antMatchers("/hello").permitAll()
       .anyRequest().authenticated()

兩種方式最大的區別在于,第一種方式是不走 Spring Security 過濾器鏈,而第二種方式走 Spring Security 過濾器鏈,在過濾器鏈中,給請求放行。

在我們使用 Spring Security 的時候,有的資源可以使用第一種方式額外放行,不需要驗證,例如前端頁面的靜態資源,就可以按照第一種方式配置放行。

有的資源放行,則必須使用第二種方式,例如登錄接口。大家知道,登錄接口也是必須要暴露出來的,不需要登錄就能訪問到的,但是我們卻不能將登錄接口用第一種方式暴露出來,登錄請求必須要走 Spring Security 過濾器鏈,因為在這個過程中,還有其他事情要做。

接下來我以登錄接口為例,來和小伙伴們分析一下走 Spring Security 過濾器鏈有什么不同。

2.登錄請求分析

首先大家知道,當我們使用 Spring Security,用戶登錄成功之后,有兩種方式獲取用戶登錄信息:

  1. SecurityContextHolder.getContext().getAuthentication()

  2. 在 Controller 的方法中,加入 Authentication 參數

這兩種辦法,都可以獲取到當前登錄用戶信息。

這兩種方式獲取到的數據都是來自 SecurityContextHolder,SecurityContextHolder 中的數據,本質上是保存在 ThreadLocal 中,ThreadLocal 的特點是存在它里邊的數據,哪個線程存的,哪個線程才能訪問到。

這樣就帶來一個問題,當用戶登錄成功之后,將用戶用戶數據存在 SecurityContextHolder 中(thread1),當下一個請求來的時候(thread2),想從 SecurityContextHolder 中獲取用戶登錄信息,卻發現獲取不到!為啥?因為它倆不是同一個 Thread。

但實際上,正常情況下,我們使用 Spring Security 登錄成功后,以后每次都能夠獲取到登錄用戶信息,這又是怎么回事呢?

這我們就要引入 Spring Security 中的 
SecurityContextPersistenceFilter 了。

小伙伴們都知道,無論是 Spring Security 還是 Shiro,它的一系列功能其實都是由過濾器來完成的,在 Spring Security 中,前面跟大家聊了 
UsernamePasswordAuthenticationFilter 過濾器,在這個過濾器之前,還有一個過濾器就是
SecurityContextPersistenceFilter,請求在到達 
UsernamePasswordAuthenticationFilter 之前都會先經過 
SecurityContextPersistenceFilter。

我們來看下它的源碼(部分):

public class SecurityContextPersistenceFilter extends GenericFilterBean {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
response);
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
SecurityContext contextAfterChainExecution = SecurityContextHolder
.getContext();
SecurityContextHolder.clearContext();
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
holder.getResponse());
}
}
}

原本的方法很長,我這里列出來了比較關鍵的幾個部分:

  1. SecurityContextPersistenceFilter 繼承自 GenericFilterBean,而 GenericFilterBean 則是 Filter 的實現,所以 SecurityContextPersistenceFilter 作為一個過濾器,它里邊最重要的方法就是 doFilter 了。

  2. 在 doFilter 方法中,它首先會從 repo 中讀取一個 SecurityContext 出來,這里的 repo 實際上就是 HttpSessionSecurityContextRepository,讀取 SecurityContext 的操作會進入到 readSecurityContextFromSession 方法中,在這里我們看到了讀取的核心方法 Object contextFromSession = httpSession.getAttribute(springSecurityContextKey);,這里的 springSecurityContextKey 對象的值就是 SPRING_SECURITY_CONTEXT,讀取出來的對象最終會被轉為一個 SecurityContext 對象。

  3. SecurityContext 是一個接口,它有一個唯一的實現類 SecurityContextImpl,這個實現類其實就是用戶信息在 session 中保存的 value。

  4. 在拿到 SecurityContext 之后,通過 SecurityContextHolder.setContext 方法將這個 SecurityContext 設置到 ThreadLocal 中去,這樣,在當前請求中,Spring Security 的后續操作,我們都可以直接從 SecurityContextHolder 中獲取到用戶信息了。

  5. 接下來,通過 chain.doFilter 讓請求繼續向下走(這個時候就會進入到 UsernamePasswordAuthenticationFilter 過濾器中了)。

  6. 在過濾器鏈走完之后,數據響應給前端之后,finally 中還有一步收尾操作,這一步很關鍵。這里從 SecurityContextHolder 中獲取到 SecurityContext,獲取到之后,會把 SecurityContextHolder 清空,然后調用 repo.saveContext 方法將獲取到的 SecurityContext 存入 session 中。

至此,整個流程就很明了了。

每一個請求到達服務端的時候,首先從 session 中找出來 SecurityContext ,然后設置到 SecurityContextHolder 中去,方便后續使用,當這個請求離開的時候,SecurityContextHolder 會被清空,SecurityContext 會被放回 session 中,方便下一個請求來的時候獲取。

登錄請求來的時候,還沒有登錄用戶數據,但是登錄請求走的時候,會將用戶登錄數據存入 session 中,下個請求到來的時候,就可以直接取出來用了。

看了上面的分析,我們可以至少得出兩點結論:

  1. 如果我們暴露登錄接口的時候,使用了前面提到的第一種方式,沒有走 Spring Security,過濾器鏈,則在登錄成功后,就不會將登錄用戶信息存入 session 中,進而導致后來的請求都無法獲取到登錄用戶信息(后來的請求在系統眼里也都是未認證的請求)

  2. 如果你的登錄請求正常,走了 Spring Security 過濾器鏈,但是后來的 A 請求沒走過濾器鏈(采用前面提到的第一種方式放行),那么 A 請求中,也是無法通過 SecurityContextHolder 獲取到登錄用戶信息的,因為它一開始沒經過 SecurityContextPersistenceFilter 過濾器鏈。

3.總結

總之,前端靜態資源放行時,可以直接不走 Spring Security 過濾器鏈,像下面這樣:

@Override
public void configure(WebSecurity web) throws Exception {
   web.ignoring().antMatchers("/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico");
}

后端的接口要額外放行,就需要仔細考慮場景了,不過一般來說,不建議使用上面這種方式,建議下面這種方式,原因前面已經說過了:

http.authorizeRequests()
       .antMatchers("/hello").permitAll()
       .anyRequest().authenticated()

到此,相信大家對“Spring Security資源放行策略有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

双城市| 嘉兴市| 东丽区| 孟津县| 石楼县| 绥滨县| 加查县| 定安县| 湄潭县| 汝阳县| 宣武区| 兴义市| 长丰县| 白朗县| 呼伦贝尔市| 舞阳县| 城固县| 高陵县| 乐亭县| 鹤岗市| 临沂市| 普宁市| 桂阳县| 晋宁县| 崇文区| 兴隆县| 仪征市| 鹰潭市| 阜宁县| 宁陵县| 青浦区| 西安市| 中牟县| 绥棱县| 高邮市| 浦东新区| 霍邱县| 清流县| 甘德县| 贵南县| 随州市|