日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring Security源碼解析之權限訪問控制是如何做到的

瀏覽:141日期:2023-07-14 17:58:54
目錄?、前文回顧一、再聊過濾器鏈二、過濾器的創建FilterSecurityInterceptor的創建ExceptionTranslationFilter的創建三、源碼流程FilterSecurityInterceptorExceptionTranslationFilter四、總結?、前文回顧

在實戰篇《話說Spring Security權限管理(源碼詳解)》我們學習了Spring Security強大的訪問控制能力,只需要進行寥寥幾行的配置就能做到權限的控制,本篇來看看它到底是如何做到的。

一、再聊過濾器鏈

源碼篇中反復提到,請求進來需要經過的是一堆過濾器形成的過濾器鏈,走完過濾器鏈未拋出異常則可以繼續訪問后臺接口資源,而最后一個過濾器就是來判斷請求是否有權限繼續訪問后臺資源,如果沒有則會將拒絕訪問的異常往上向異常過濾器拋,異常過濾器會對異常進行翻譯,然后響應給客戶端。

所以,一般情況下最后一個過濾器是做權限訪問控制的核心過濾器FilterSecurityInterceptor ,而倒數第二個是異常翻譯過濾器ExceptionTranslationFilter ,將異常進行翻譯然后響應給客戶端。比如我們實戰項目過濾器鏈圖解

Spring Security源碼解析之權限訪問控制是如何做到的

二、過濾器的創建FilterSecurityInterceptor的創建

這個過濾器的配置器是 ExpressionUrlAuthorizationConfigurer ,它的父類 AbstractInterceptUrlConfigurer 中的 configure() 方法創建了這個過濾器。

abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>extends AbstractHttpConfigurer<C, H> {...@Overridepublic void configure(H http) throws Exception {FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);if (metadataSource == null) {return;}FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource, http.getSharedObject(AuthenticationManager.class));if (filterSecurityInterceptorOncePerRequest != null) {securityInterceptor.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);}securityInterceptor = postProcess(securityInterceptor);http.addFilter(securityInterceptor);http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);}...}

這個過濾器的配置器是在 HttpSecurity 的 authorizeRequests() 方法中apply進來的,在我們自己配置的核心配置器中使用的就是該種基于 HttpServletRequest 限制訪問的方式。

Spring Security源碼解析之權限訪問控制是如何做到的

ExceptionTranslationFilter的創建

這個過濾器的配置器是 ExceptionHandlingConfigurer ,它自己的 configure() 方法中創建了這個過濾器。

public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>> extendsAbstractHttpConfigurer<ExceptionHandlingConfigurer<H>, H> {...@Overridepublic void configure(H http) throws Exception {AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint, getRequestCache(http));if (accessDeniedHandler != null) {exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);}exceptionTranslationFilter = postProcess(exceptionTranslationFilter);http.addFilter(exceptionTranslationFilter);}...}

這個過濾器的配置器是在 HttpSecurity 的 exceptionHandling() 方法中apply進來的,和上面不同的是,這個過濾器配置器會默認被apply進 HttpSecurity,在 WebSecurityConfigurerAdapter 中的 init() 方法,里面調用了 getHttp() 方法,這里定義了很多默認的過濾器配置,其中就包括當前過濾器配置。

Spring Security源碼解析之權限訪問控制是如何做到的

三、源碼流程FilterSecurityInterceptor 進入:doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 進入:invoke(FilterInvocation fi) 進入:beforeInvocation(Object object)

這個方法里面有個 attributes ,里面獲取的就是當前request請求所能匹配中的權限Spel表達式,比如這里是 hasRole(’ROLE_BUYER’)Spring Security源碼解析之權限訪問控制是如何做到的 方法源碼如下,繼續往下走

protected InterceptorStatusToken beforeInvocation(Object object) {...// 獲取當前request請求所能匹配中的權限Spel表達式Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);...// Attempt authorizationtry {this.accessDecisionManager.decide(authenticated, object, attributes);}catch (AccessDeniedException accessDeniedException) {publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,accessDeniedException));throw accessDeniedException;}...}

進入:decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)

這里有個投票器,投票結果為1表示可以訪問直接返回,投票結果為-1表示拒絕訪問,向上拋拒絕訪問異常,這里使用的投票器是 WebExpressionVoter

public void decide(Authentication authentication, Object object,Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {int deny = 0;for (AccessDecisionVoter voter : getDecisionVoters()) {int result = voter.vote(authentication, object, configAttributes);if (logger.isDebugEnabled()) {logger.debug('Voter: ' + voter + ', returned: ' + result);}switch (result) {case AccessDecisionVoter.ACCESS_GRANTED:return;case AccessDecisionVoter.ACCESS_DENIED:deny++;break;default:break;}}if (deny > 0) {throw new AccessDeniedException(messages.getMessage('AbstractAccessDecisionManager.accessDenied', 'Access is denied'));}// To get this far, every AccessDecisionVoter abstainedcheckAllowIfAllAbstainDecisions();}

進入:vote(Authentication authentication, FilterInvocation fi, Collection<ConfigAttribute> attributes)

這里面其實就是使用Spring的Spel表達式進行投票,使用請求中的權限表達式組裝Expression,使用Token令牌中的權限組裝EvaluationContext,然后調用 ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx),

public int vote(Authentication authentication, FilterInvocation fi,Collection<ConfigAttribute> attributes) {assert authentication != null;assert fi != null;assert attributes != null;WebExpressionConfigAttribute weca = findConfigAttribute(attributes);if (weca == null) {return ACCESS_ABSTAIN;}EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,fi);ctx = weca.postProcess(ctx, fi);return ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED: ACCESS_DENIED;}

evaluateAsBoolean() 方法里面就是調用Expression的 getValue() 方法,獲取實際的匹配結果,如下圖Spel表達式為 hasRole(’ROLE_BUYER’)Spring Security源碼解析之權限訪問控制是如何做到的所以它實際調用的是 SecurityExpressionRoot#hasRole 方法(關于權限表達式對應實際調用的方法,在《手把手教你如何使用Spring Security(下):訪問控制》文章中已貼出,下面文章也補充一份),里面的邏輯其實就是判斷Token令牌中是否包含有 ROLE_BUYER 的角色,有的話返回true,否則返回false,如下為 SecurityExpressionRoot#hasRole 方法源碼:

private boolean hasAnyAuthorityName(String prefix, String... roles) {Set<String> roleSet = getAuthoritySet();for (String role : roles) {String defaultedRole = getRoleWithDefaultPrefix(prefix, role);if (roleSet.contains(defaultedRole)) {return true;}}return false;} 如果投票成功,則會一直返回到 invoke() 方法,再執行后續過濾器,未拋異常表示該請求已經有訪問權限了 假如投票失敗,在 decide() 方法中會向上拋拒絕訪問異常,一直往上拋直到被處理,往上反向跟蹤發現這個過濾器一直沒有處理拒絕訪問異常,那就繼續往上個過濾器拋,就到了我們的異常翻譯過濾器 ExceptionTranslationFilter。ExceptionTranslationFilter

該過濾器的 doFilter() 方法很簡單,沒有邏輯處理,只對后續過濾器拋出的異常進行處理,源碼如下:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;try {chain.doFilter(request, response);logger.debug('Chain processed normally');}catch (IOException ex) {throw ex;}catch (Exception ex) {// Try to extract a SpringSecurityException from the stacktraceThrowable[] causeChain = throwableAnalyzer.determineCauseChain(ex);RuntimeException ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);if (ase == null) {ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);}if (ase != null) {handleSpringSecurityException(request, response, chain, ase);}else {// Rethrow ServletExceptions and RuntimeExceptions as-isif (ex instanceof ServletException) {throw (ServletException) ex;}else if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}// Wrap other Exceptions. This shouldn’t actually happen// as we’ve already covered all the possibilities for doFilterthrow new RuntimeException(ex);}}}

當拋出拒絕訪問異常后,繼續調用 handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) 方法,方法里面主要將異常信息和錯誤碼設置到響應頭,然后響應到客戶端,請求結束。

補充:權限表達式

權限表達式(ExpressionUrlAuthorizationConfigurer) 說明 Spel表達式 Spel表達式實際執行方法(SecurityExpressionOperations) permitAll() 表示允許所有,永遠返回true permitAll permitAll() denyAll() 表示拒絕所有,永遠返回false denyAll denyAll() anonymous() 當前用戶是anonymous時返回true anonymous isAnonymous() rememberMe() 當前用戶是rememberMe用戶時返回true rememberMe isRememberMe() authenticated() 當前用戶不是anonymous時返回true authenticated isAuthenticated() fullyAuthenticated() 當前用戶既不是anonymous也不是rememberMe用戶時返回true fullyAuthenticated isFullyAuthenticated() hasRole(“BUYER”) 用戶擁有指定權限時返回true hasRole(‘ROLE_BUYER’) hasRole(String role) hasAnyRole(“BUYER”,“SELLER”) 用于擁有任意一個角色權限時返回true hasAnyRole (‘ROLE_BUYER’,‘ROLE_BUYER’) hasAnyRole(String… roles) hasAuthority(“BUYER”) 同hasRole hasAuthority(‘ROLE_BUYER’) hasAuthority(String role) hasAnyAuthority(“BUYER”,“SELLER”) 同hasAnyRole hasAnyAuthority (‘ROLE_BUYER’,‘ROLE_BUYER’) hasAnyAuthority(String… authorities) hasIpAddress(‘192.168.1.0/24’) 請求發送的Ip匹配時返回true hasIpAddress(‘192.168.1.0/24’) hasIpAddress(String ipAddress),該方法在WebSecurityExpressionRoot類中 access('@rbacService.hasPermission(request, authentication)') 可以自定義Spel表達式 @rbacService.hasPermission (request, authentication) hasPermission(request, authentication) ,該方法在自定義的RbacServiceImpl類中 四、總結 訪問控制的核心過濾器是 FilterSecurityInterceptor ,當然這個是可選的,我們完全也可以自定義一個過濾器去處理權限訪問。 處理訪問異常處理的過濾器是 ExceptionTranslationFilter ,里面邏輯很簡單,給response設置異常信息錯誤碼,再返回給客戶端。

以上就是Spring Security源碼解析之權限訪問控制是如何做到的的詳細內容,更多關于Spring Security權限訪問控制的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
麻豆国产欧美一区二区三区| 91看片一区| 精品少妇一区| 欧美在线精品一区| 日韩中文字幕亚洲一区二区va在线 | 最新国产精品| 野花国产精品入口| 久久国产小视频| 欧美日韩免费看片| 波多视频一区| 午夜av成人| 日韩一区三区| 精品国产黄a∨片高清在线| 国产精品伦一区二区| 欧美精品中文字幕亚洲专区| 日本中文字幕视频一区| 亚洲三级av| 婷婷精品在线| 奶水喷射视频一区| 欧美国产一级| 久久精品成人| 五月婷婷六月综合| 99热精品在线观看| 免费视频最近日韩| 日本不卡一二三区黄网| 日本99精品| 麻豆精品久久| 麻豆网站免费在线观看| 一区二区精品伦理...| 日韩av二区| 日韩欧美二区| 亚洲黑丝一区二区| 亚洲激情中文| 欧美日韩视频| 国产专区一区| 久久成人国产| 欧美偷窥清纯综合图区| 国产精品高潮呻吟久久久久| 国产精品扒开腿做爽爽爽软件| 精品一区二区男人吃奶| 涩涩av在线| 日韩视频精品在线观看| 亚洲精品一级二级三级| 欧美久久香蕉| 国产伦久视频在线观看| 91精品99| 伊人久久一区| 精品伊人久久| 超级白嫩亚洲国产第一| 久久精品中文| 三级欧美在线一区| 日韩超碰人人爽人人做人人添| 久久精品人人| 欧美日韩四区| 国产精品一区二区av日韩在线| 国产精品专区免费| 日本大胆欧美人术艺术动态| 国产精品久久久久久久久久久久久久久| 精品香蕉视频| 亚洲精品一区二区妖精| 欧美精品国产一区| 久久激情网站| 日本午夜精品久久久| 日本v片在线高清不卡在线观看| 91免费精品国偷自产在线在线| av高清不卡| 日韩欧美久久| 成人在线免费观看91| 欧美日韩国产精品一区二区亚洲| 亚洲精选久久| 色乱码一区二区三区网站| 免费在线观看视频一区| 国内精品麻豆美女在线播放视频| 9国产精品视频| 精品三级av在线导航| 亚洲资源av| 精品国产一区二区三区av片| 欧美福利一区| 国产福利资源一区| 91精品一区国产高清在线gif| 亚洲欧美专区| 99久久精品费精品国产| 国产九一精品| 蜜臀久久99精品久久久久久9| 国产精品成人一区二区不卡| 国产一区二区精品| 91嫩草精品| 蜜臀久久99精品久久一区二区| 欧美日韩18| 丝袜a∨在线一区二区三区不卡| а√天堂中文在线资源8| 亚洲综合福利| 91精品成人| 国产精品久久久久久久久久10秀| 五月婷婷六月综合| 欧美aa在线观看| 日韩欧美精品一区二区综合视频| 精品久久影院| 国产日本久久| 亚洲1区在线观看| 免费日韩视频| 蜜桃tv一区二区三区| 国产精品麻豆久久| 久久免费影院| 国产极品嫩模在线观看91精品| 国产精品美女| 欧美国产小视频| 麻豆精品蜜桃视频网站| 日韩高清在线不卡| 日韩午夜精品| 日韩在线短视频| av资源新版天堂在线| 欧美1区2区3| 国产乱码精品一区二区三区亚洲人| 热久久国产精品| 亚洲一区区二区| 亚洲激情精品| 午夜精品成人av| 国产精品亚洲综合在线观看| 日韩中文一区二区| 亚洲午夜免费| 免费人成网站在线观看欧美高清| 最新亚洲激情| 日韩一区二区久久| 久久国产日韩| 免费av一区二区三区四区| 成人片免费看| 午夜av成人| 99久久亚洲精品蜜臀| 黄色在线观看www| 人人香蕉久久| 亚洲夜间福利| 国产精品美女久久久| 亚洲欧美不卡| 亚洲精品国产精品粉嫩| 蜜桃av一区二区三区电影| 欧美a级一区| 噜噜噜躁狠狠躁狠狠精品视频| 国产亚洲亚洲| 先锋亚洲精品| 中文字幕一区二区三区日韩精品 | 亚洲2区在线| 97久久中文字幕| 日本中文字幕不卡| 国产精品一区二区中文字幕| 国产精品久久久免费| 精品免费视频| 美女视频黄免费的久久| 久久久久久网| 伊人久久大香伊蕉在人线观看热v| 久久国产人妖系列| 丁香婷婷久久| 亚洲区第一页| 日韩精品看片| 国产亚洲欧美日韩精品一区二区三区 | 国产日本精品| 狠狠爱成人网| 国产精品a级| 午夜在线精品偷拍| 精品网站999| 中文字幕日韩高清在线| 亚洲免费福利| 国产精品一区二区三区www| 亚洲啊v在线| 日韩一区二区三免费高清在线观看| 高潮久久久久久久久久久久久久| 国产亚洲毛片在线| 美腿丝袜在线亚洲一区| 亚洲欧美视频一区二区三区| 精品久久久久中文字幕小说| 免费人成精品欧美精品| 午夜久久中文| 久久99精品久久久久久园产越南| 99国产精品99久久久久久粉嫩| 狠狠久久伊人| 日韩av中文在线观看| 欧美午夜不卡影院在线观看完整版免费| 国产精品一国产精品k频道56| 亚洲网站视频| 都市激情国产精品| 国产日韩亚洲| 日韩欧美美女在线观看| 亚洲精品午夜av福利久久蜜桃| 国产盗摄——sm在线视频| 国产剧情一区| 91精品丝袜国产高跟在线| 丝袜亚洲精品中文字幕一区| 久久在线视频免费观看| 成人国产精品一区二区免费麻豆| 欧美日韩中出| 奇米亚洲欧美| 午夜天堂精品久久久久| 好吊一区二区三区| 精品网站999| 久久一区视频| 国产精品黄网站| 国产精品视频一区视频二区| 日韩欧美中文字幕电影| 一区二区三区网站| 免费中文字幕日韩欧美|