日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springSecurity的登录验证

發布時間:2024/1/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springSecurity的登录验证 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:http://www.cnblogs.com/hzhuxin/archive/2011/12/14/2287363.html

springSecurity的登錄驗證是由org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter這個過濾器來完成的,在該類的父類AbstractAuthenticationProcessingFilter中有一個AuthenticationManager接口屬性,驗證工作主要是通過這個AuthenticationManager接口的實例來完成的。在默認情況下,springSecurity框架會把org.springframework.security.authentication.ProviderManager類的實例注入到該屬性,

AuthenticationManager接口的相關類圖如下:

UsernamePasswordAuthenticationFilter的驗證過程如下:

1. 首先過濾器會調用自身的attemptAuthentication方法,從request中取出authentication, authentication是在org.springframework.security.web.context.SecurityContextPersistenceFilter過濾器中通過捕獲用戶提交的登錄表單中的內容生成的一個org.springframework.security.core.Authentication接口實例.

2. 拿到authentication對象后,過濾器會調用ProviderManager類的authenticate方法,并傳入該對象

3.ProviderManager類的authenticate方法再調用自身的doAuthentication方法,在doAuthentication方法中會調用類中的List<AuthenticationProvider> providers集合中的各個AuthenticationProvider接口實現類中的authenticate(Authentication authentication)方法進行驗證,由此可見,真正的驗證邏輯是由各個各個AuthenticationProvider接口實現類來完成的,DaoAuthenticationProvider類是默認情況下注入的一個AuthenticationProvider接口實現類

4.AuthenticationProvider接口通過UserDetailsService來獲取用戶信息

以下為時序圖:


文章2:

工作需要,又弄起了權限的管理。雖然很早以前都了解過基于容器的權限實現方式,但是一直都覺得那東西太簡陋了。后來使用liferay時發現它的權限系統的確做得很優秀,感覺這也可能是它做得最出色的地方吧。但是當時只停留在怎么使用及一些與其銜接的關系之上,并沒有對其底層進行了解,新到現在的公司后,發現這一課還是得補上。但是令人驚訝的是,目前可用的選擇并不多,甚至很少,最有名的當屬spring security了,雖然很有名,但是關于這方面的資料并不是很多,應用示例就更少了。還好有中文的官方文檔與http://www.family168.com/bbs/發布的簡要教程,因此學起來不至于太困難。然后參照了一篇downpour寫的spring security文章,因此勉強熟悉了spring security的應用開發,但是基本只停留在勉強會用的基礎之上,而且還花了本人不少時間,在一個項目的運用中,自己更是差點沒下得了臺,驚出了一身冷汗。當時的感覺spring security就是個垃圾東西,運用很復雜,哪怕是做一個只攔截路徑的權限系統,也要經過很多步驟。現在熟悉了它的一些流程后,雖然不知道這樣的實現方式是否是最合理的,但是的確也有它的道理。現在利用放假期間,可以靜下心來,理解一些以前讓自己迷惑的東西了。downpour牛人的那篇文章講得很好,以至于本人著實花了點時間才把它完全熟悉,當前自己以前對acegi并不熟悉。熟悉了那篇文章后,還是有些地方讓自己不太理解,其中之一就是spring security是怎樣完成用戶角色權限驗證的。下面就對這人問題進行簡單的介紹:?

首先這篇文章是基于downpour那篇文章的,其地址為:?
http://www.iteye.com/topic/319965?

最先著手就是配置文件,這也是整個spring security最重要的入口點:?

Xml代碼??
  • ............??
  • <!--??處理國際化信息?-->??
  • ????<beans:bean?id="authenticationManager"??
  • ????????class="org.springframework.security.providers.ProviderManager">??
  • ????????<beans:property?name="messageSource"?ref="messageSource"?/>??
  • ????</beans:bean>??
  • ??????
  • ????<beans:bean?id="messageSource"??
  • ????????class="org.springframework.context.support.ReloadableResourceBundleMessageSource">??
  • ????????<beans:property?name="basename"??
  • ????????????value="classpath:org/springframework/security/messages_zh_CN"?/>??
  • ????</beans:bean>??
  • ??
  • ????<authentication-provider?user-service-ref="securityManager">??
  • ????????<password-encoder?hash="md5"?/>??
  • ????</authentication-provider>??
  • ??
  • <!--?AffirmativeBased表示只要有一個Voter通過權限要求,就可以訪問?-->??
  • ????<beans:bean?id="accessDecisionManager"??
  • ????????class="org.springframework.security.vote.AffirmativeBased">??
  • ????????<!--?是否允許所有的投票者棄權,如果為false,表示如果所有的投票者棄權,就禁止訪問?-->??
  • ????????<beans:property?name="allowIfAllAbstainDecisions"??
  • ????????????value="false"?/>??
  • ????????<beans:property?name="decisionVoters">??
  • ????????????<beans:list>??
  • <!--?RoleVoter默認角色名稱都要以ROLE_開頭,否則不會被計入權限控制,如果要修改前綴,可以通過對rolePrefix屬性進行修改?-->??
  • ????????????????<beans:bean?class="org.springframework.security.vote.RoleVoter"?/>??
  • ????????????????<beans:bean?class="org.springframework.security.vote.AuthenticatedVoter"?/>??
  • ????????????</beans:list>??
  • ????????</beans:property>??
  • ????</beans:bean>??
  • ??
  • ????<beans:bean?id="resourceSecurityInterceptor"??
  • ????????class="org.springframework.security.intercept.web.FilterSecurityInterceptor">??
  • ????????<beans:property?name="authenticationManager"?ref="authenticationManager"?/>??
  • ????????<beans:property?name="accessDecisionManager"?ref="accessDecisionManager"?/>??
  • ????????<beans:property?name="objectDefinitionSource"??
  • ????????????ref="secureResourceFilterInvocationDefinitionSource"?/>??
  • ????????????<!--?每次請求都進行檢查,如果設為true,則只第一次檢查,默認為true?-->??
  • ????????<beans:property?name="observeOncePerRequest"?value="false"?/>??
  • ????????<custom-filter?after="LAST"?/>??
  • ????</beans:bean>??
  • ??
  • ????<beans:bean?id="secureResourceFilterInvocationDefinitionSource"??
  • ????????class="com.javaeye.sample.security.interceptor.SecureResourceFilterInvocationDefinitionSource"?/>??
  • ....??


  • 上面的“accessDecisionManager”就是切入點,首先需要說明的是,在驗證用戶是否能通過驗證時,spring security提供了三種策略,分別對應那個策略類:?
    UnanimousBased.java 只要有一個Voter不能完全通過權限要求,就禁止訪問。?
    AffirmativeBased.java只要有一個Voter可以通過權限要求,就可以訪問。?
    ConsensusBased.java只要通過的Voter比禁止的Voter數目多就可以訪問了。?

    在此說一點,ConsensusBased這個類有點特別,如果通過的票數與禁止的票數相同怎么辦??
    這個類有個allowIfEqualGrantedDeniedDecisions屬性,默認為true,關鍵代碼:?

    Java代碼??
  • if?((grant?==?deny)?&&?(grant?!=?0))?{??
  • ????????????if?(this.allowIfEqualGrantedDeniedDecisions)?{??
  • ????????????????return;??
  • ????????????}?else?{??
  • ????????????????throw?new?AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",??
  • ????????????????????????"Access?is?denied"));??
  • ????????????}??
  • ????????}??


  • 上面的代碼表示如果allowIfEqualGrantedDeniedDecisions為true而且通過的票數不為0就授權訪問。?

    在提供好驗證策略以后,繼續關注其是怎么進行驗證的。在上面的XML文件中,accessDescisionManager有個allowIfAllAbstainDecisions屬性,這個屬性的默認值為false,作用見注釋處。現在主要關注的是其decisionVoters屬性,中文的理解就是投票,RoleVoter.java 主要作用就是完成角色的投票驗證,需要注意的是,它驗證的角色,名稱必須以ROLE_開頭,當然這也可以通過配置文件改變,如:?

    Xml代碼??
  • <bean?id="roleVoter"?class="org.springframework.security.vote.RoleVoter">??
  • ????<property?name="rolePrefix"?value="AUTH_"/>??
  • </bean>??


  • 至于RoleVoter是如何完成驗證的呆會再說,先回顧一下com.javaeye.sample.security.interceptor.SecureResourceFilterInvocationDefinitionSource:?

    Java代碼??
  • .....??
  • ????public?ConfigAttributeDefinition?getAttributes(Object?filter)?throws?IllegalArgumentException?{??
  • ??????????
  • ????????FilterInvocation?filterInvocation?=?(FilterInvocation)?filter;??
  • ????????String?requestURI?=?filterInvocation.getRequestUrl();??
  • ????????Map<String,?String>?urlAuthorities?=?this.getUrlAuthorities(filterInvocation);??
  • ??????????
  • ????????String?grantedAuthorities?=?null;??
  • ????????for(Iterator<Map.Entry<String,?String>>?iter?=?urlAuthorities.entrySet().iterator();?iter.hasNext();)?{??
  • ????????????Map.Entry<String,?String>?entry?=?iter.next();??
  • ??????????????
  • ????????????//url表示從資源表取出的值,在這里代表的是相應的URL??
  • ????????????String?url?=?entry.getKey();??
  • ??????????????
  • ????????????//這段代碼表示數據庫內的需要驗證的資源URL與當前請求的URL相匹配時進行驗證??
  • ????????????if(urlMatcher.pathMatchesUrl(url,?requestURI))?{??
  • ????????????????//grantedAuthorities表示每個資源對應的角色,如果有多個角色,則以','隔開??
  • ????????????????grantedAuthorities?=?entry.getValue();??
  • ????????????????break;??
  • ????????????}??
  • ????????}??
  • ??????????
  • ????????if(grantedAuthorities?!=?null)?{??
  • ????????????ConfigAttributeEditor?configAttrEditor?=?new?ConfigAttributeEditor();??
  • ????????????configAttrEditor.setAsText(grantedAuthorities);??
  • ????????????return?(ConfigAttributeDefinition)?configAttrEditor.getValue();??
  • ????????}??
  • ????????return?null;??
  • ????}??
  • ....??


  • 雖然不重要,但是還是有必要引用一下:?

    引用
    處于繼承樹頂端的AbstractSecurityInterceptor有三個實現類:?

    FilterSecurityInterceptor,負責處理FilterInvocation,實現對URL資源的攔截。?
    MethodSecurityInterceptor,負責處理MethodInvocation,實現對方法調用的攔截。?
    AspectJSecurityInterceptor,負責處理JoinPoint,主要也是用于對方法調用的攔截。?

    為了限制用戶訪問被保護資源,Spring Security提供了一套元數據,用于定義被保護資源的訪問權限,這套元數據主要體現為ConfigAttribute和ConfigAttributeDefinition。每個ConfigAttribute中只包含一個字符串,而一個ConfigAttributeDefinition中可以包含多個ConfigAttribute。對于系統來說,每個被保護資源都將對應一個ConfigAttributeDefinition,這個ConfigAttributeDefinition中包含的多個ConfigAttribute就是訪問該資源所需的權限。?

    實際應用中,ConfigAttributeDefinition會保存在ObjectDefinitionSource中,這是一個主要接口,FilterSecurityInterceptor所需的DefaultFilterInvocationDefinitionSource和MethodSecurityInterceptor所需的MethodDefinitionAttributes都實現了這個接口。ObjectDefinitionSource可以看做是Spring Security中權限配置的源頭,框架內部所有的驗證組件都是從ObjectDefintionSource中獲得數據,來對被保護資源進行權限控制的。?

    為了從xml中將用戶配置的訪問權限轉換成ObjectDefinitionSource類型的對象,Spring Security專門擴展了Spring中提供的PropertyEditor實現了ConfigAttributeEditor,它可以把以逗號分隔的一系列字符串轉換成包含多個ConfigAttribute的ConfigAttributeDefintion對象。?

    "ROLE_ADMIN,ROLE_USER"?

    ↓?

    ConfigAttributeDefinition?
    ? ConfigAttribute["ROLE_ADMIN"]?
    ? ConfigAttribute["ROLE_USER"]?
    ????????
    對于FilterSecurityInterceptor來說,最終生成的就是一個包含了url pattern和ConfigAttributeConfiguration的ObjectDefinitionSource。?


    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN,ROLE_USER" />?

    ↓?

    ??????????????????? ConfigAttributeDefinition?
    "/admin.jsp"?? →???? ConfigAttribute["ROLE_ADMIN"]?
    ????????????????????? ConfigAttribute["ROLE_USER"]?
    ????????
    換而言之,無論我們將權限配置的原始數據保存在什么地方,只要最終可以將其轉換為ObjectDefintionSource就可以提供給驗證組件進行調用,實現權限控制。?



    當時一直不明白這個getAttributes到底拿來做什么的。下面一步步進行追終,通過配置文件可知,這個類首先會到org.springframework.security.intercept.web.FilterSecurityInterceptor這個類中,這個類有個主要的方法:?

    Java代碼??
  • public?void?invoke(FilterInvocation?fi)?throws?IOException,?ServletException?{??
  • ???????if?((fi.getRequest()?!=?null)?&&?(fi.getRequest().getAttribute(FILTER_APPLIED)?!=?null)??
  • ???????????&&?observeOncePerRequest)?{??
  • ???????????//?filter?already?applied?to?this?request?and?user?wants?us?to?observce??
  • ???????????//?once-per-request?handling,?so?don't?re-do?security?checking??
  • ???????????fi.getChain().doFilter(fi.getRequest(),?fi.getResponse());??
  • ???????}?else?{??
  • ???????????//?first?time?this?request?being?called,?so?perform?security?checking??
  • ???????????if?(fi.getRequest()?!=?null)?{??
  • ???????????????fi.getRequest().setAttribute(FILTER_APPLIED,?Boolean.TRUE);??
  • ???????????}??
  • ??
  • ???????????InterceptorStatusToken?token?=?super.beforeInvocation(fi);??
  • ??
  • ???????????try?{??
  • ???????????????fi.getChain().doFilter(fi.getRequest(),?fi.getResponse());??
  • ???????????}?finally?{??
  • ???????????????super.afterInvocation(token,?null);??
  • ???????????}??
  • ???????}??
  • ???}??


  • 在此有兩點需要說明,首先是observeOncePerRequest屬性,一般情況下保持其默認的true,文檔上有說:?

    Java代碼??
  • /***??
  • Indicates?whether?once-per-request?handling?will?be?observed.?By?default?this?is?<code>true</code>,meaning?the?<code>FilterSecurityInterceptor</code>?will?only?execute?once-per-request.?Sometimes?users?may?wishit?to?execute?more?than?once?per?request,?such?as?when?JSP?forwards?are?being?used?and?filter?security?is?desired?on?each?included?fragment?of?the?HTTP?request.?
  • */??


  • 其次我們需要關注的重點是FilterSecurityInterceptor的超類AbstractSecurityInterceptor的beforeInvocation方法,下面貼出這個類中我們最需要關注的代碼:?

    Java代碼??
  • protected?InterceptorStatusToken?beforeInvocation(Object?object)?{??
  • ????????Assert.notNull(object,?"Object?was?null");??
  • ??
  • ????????if?(!getSecureObjectClass().isAssignableFrom(object.getClass()))?{??
  • ????????????throw?new?IllegalArgumentException("Security?invocation?attempted?for?object?"??
  • ????????????????????+?object.getClass().getName()??
  • ????????????????????+?"?but?AbstractSecurityInterceptor?only?configured?to?support?secure?objects?of?type:?"??
  • ????????????????????+?getSecureObjectClass());??
  • ????????}??
  • ??
  • ????????ConfigAttributeDefinition?attr?=?this.obtainObjectDefinitionSource().getAttributes(object);??
  • ??
  • ????????if?(attr?==?null)?{??
  • ????????????if?(rejectPublicInvocations)?{??
  • ????????????????throw?new?IllegalArgumentException(??
  • ????????????????????????"No?public?invocations?are?allowed?via?this?AbstractSecurityInterceptor.?"??
  • ????????????????????????????????+?"This?indicates?a?configuration?error?because?the?"??
  • ????????????????????????????????+?"AbstractSecurityInterceptor.rejectPublicInvocations?property?is?set?to?'true'");??
  • ????????????}??
  • ??
  • ????????????if?(logger.isDebugEnabled())?{??
  • ????????????????logger.debug("Public?object?-?authentication?not?attempted");??
  • ????????????}??
  • ??
  • ????????????publishEvent(new?PublicInvocationEvent(object));??
  • ??
  • ????????????return?null;?//?no?further?work?post-invocation??
  • ????????}??
  • ??
  • ????????if?(logger.isDebugEnabled())?{??
  • ????????????logger.debug("Secure?object:?"?+?object?+?";?ConfigAttributes:?"?+?attr);??
  • ????????}??
  • ??
  • ????????if?(SecurityContextHolder.getContext().getAuthentication()?==?null)?{??
  • ????????????credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",??
  • ????????????????????"An?Authentication?object?was?not?found?in?the?SecurityContext"),?object,?attr);??
  • ????????}??
  • ??
  • ????????Authentication?authenticated?=?authenticateIfRequired();??
  • ??
  • ????????//?Attempt?authorization??
  • ????????try?{??
  • ????????????this.accessDecisionManager.decide(authenticated,?object,?attr);??
  • ????????}??
  • ????????catch?(AccessDeniedException?accessDeniedException)?{??
  • ????????????AuthorizationFailureEvent?event?=?new?AuthorizationFailureEvent(object,?attr,?authenticated,??
  • ????????????????????accessDeniedException);??
  • ????????????publishEvent(event);??
  • ??
  • ????????????throw?accessDeniedException;??
  • ????????}??
  • ??
  • ????????if?(logger.isDebugEnabled())?{??
  • ????????????logger.debug("Authorization?successful");??
  • ????????}??
  • ??
  • ????????AuthorizedEvent?event?=?new?AuthorizedEvent(object,?attr,?authenticated);??
  • ????????publishEvent(event);??
  • ??
  • ????????//?Attempt?to?run?as?a?different?user??
  • ????????Authentication?runAs?=?this.runAsManager.buildRunAs(authenticated,?object,?attr);??
  • ??
  • ????????if?(runAs?==?null)?{??
  • ????????????if?(logger.isDebugEnabled())?{??
  • ????????????????logger.debug("RunAsManager?did?not?change?Authentication?object");??
  • ????????????}??
  • ??
  • ????????????//?no?further?work?post-invocation??
  • ????????????return?new?InterceptorStatusToken(authenticated,?false,?attr,?object);??
  • ????????}?else?{??
  • ????????????if?(logger.isDebugEnabled())?{??
  • ????????????????logger.debug("Switching?to?RunAs?Authentication:?"?+?runAs);??
  • ????????????}??
  • ??
  • ????????????SecurityContextHolder.getContext().setAuthentication(runAs);??
  • ??
  • ????????????//?revert?to?token.Authenticated?post-invocation??
  • ????????????return?new?InterceptorStatusToken(authenticated,?true,?attr,?object);??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?Checks?the?current?authentication?token?and?passes?it?to?the?AuthenticationManager?if?
  • ?????*?{@link?org.springframework.security.Authentication#isAuthenticated()}?returns?false?or?the?property?
  • ?????*?<tt>alwaysReauthenticate</tt>?has?been?set?to?true.?
  • ?????*?
  • ?????*?@return?an?authenticated?<tt>Authentication</tt>?object.?
  • ?????*/??
  • ????private?Authentication?authenticateIfRequired()?{??
  • ????????Authentication?authentication?=?SecurityContextHolder.getContext().getAuthentication();??
  • ??
  • ????????if?(authentication.isAuthenticated()?&&?!alwaysReauthenticate)?{??
  • ????????????if?(logger.isDebugEnabled())?{??
  • ????????????????logger.debug("Previously?Authenticated:?"?+?authentication);??
  • ????????????}??
  • ??
  • ????????????return?authentication;??
  • ????????}??


  • 上面的代碼首先關注其中的一行代碼:?

    Java代碼??
  • ConfigAttributeDefinition?attr?=?this.obtainObjectDefinitionSource().getAttributes(object);??


  • 不錯,這行代碼就是SecureResourceFilterInvocationDefinitionSource存在的主要目的,它主要提供URL與ROLE這兩個東西,至于需要驗證的用戶來源,上面有句代碼:?
    Java代碼??
  • Authentication?authentication?=?SecurityContextHolder.getContext().getAuthentication();??


  • 眾所周知,用戶登陸成功后,可以通過:?

    Java代碼??
  • (User)?SecurityContextHolder.getContext().getAuthentication().getPrincipal();??


  • 上面的代碼可以獲取當前登陸的用戶的基本信息,所以驗證時需要它也很自然的。既然所需要的東西都具備了,下面就講講該怎么驗證的問題了。在上面的AbstractSecurityInterceptor內,有句代碼:?
    Java代碼??
  • this.accessDecisionManager.decide(authenticated,?object,?attr);??


  • 上面這個accessDecisionManager就是最開始講的那個accessDecisionManager,終于回到原來的問題上了,由于上面的配置文件中使用了AffirmativeBased投票策略,下面就直接進入此類的decide方法:?
    Java代碼??
  • public?void?decide(Authentication?authentication,?Object?object,?ConfigAttributeDefinition?config)??
  • ????????throws?AccessDeniedException?{??
  • ????????Iterator?iter?=?this.getDecisionVoters().iterator();??
  • ????????int?deny?=?0;??
  • ??
  • ????????while?(iter.hasNext())?{??
  • ????????????AccessDecisionVoter?voter?=?(AccessDecisionVoter)?iter.next();??
  • ????????????int?result?=?voter.vote(authentication,?object,?config);??
  • ??
  • ????????????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?abstained??
  • ????????checkAllowIfAllAbstainDecisions();??
  • ????}??


  • 這個方法主要有三個作用,第一作用就是完成投票,第二就是驗證,從上面的switch與if語句可以看出,只要有一個投票者贊成,就直接返回,驗證通過。如果沒有一個投票者贊成(棄權)而且有人反對,deny++,到if(deny>0)時扔出異常,最后禁止訪問。最后一句?

    Java代碼??
  • //到這步時,所有的投票者都棄權了??
  • //?To?get?this?far,?every?AccessDecisionVoter?abstained??
  • ????????checkAllowIfAllAbstainDecisions();??


  • 這就到了allowIfAllAbstainDecisions屬性起作用的時候了。下面就來講講AffirmativeBased中用到的投票類RoleVoter,這個類主要工作就是完成投票工作,然后將結果反饋給AffirmativeBased,下面列出RoleVoter的代碼:?

    Java代碼??
  • public?class?RoleVoter?implements?AccessDecisionVoter?{??
  • ????//~?Instance?fields?================================================================================================??
  • ??
  • ????private?String?rolePrefix?=?"ROLE_";??
  • ??
  • ????//~?Methods?========================================================================================================??
  • ??
  • ????public?String?getRolePrefix()?{??
  • ????????return?rolePrefix;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?Allows?the?default?role?prefix?of?<code>ROLE_</code>?to?be?overridden.?
  • ?????*?May?be?set?to?an?empty?value,?although?this?is?usually?not?desirable.?
  • ?????*?
  • ?????*?@param?rolePrefix?the?new?prefix?
  • ?????*/??
  • ????public?void?setRolePrefix(String?rolePrefix)?{??
  • ????????this.rolePrefix?=?rolePrefix;??
  • ????}??
  • ??
  • ????public?boolean?supports(ConfigAttribute?attribute)?{??
  • ????????if?((attribute.getAttribute()?!=?null)?&&?attribute.getAttribute().startsWith(getRolePrefix()))?{??
  • ????????????return?true;??
  • ????????}??
  • ????????else?{??
  • ????????????return?false;??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?This?implementation?supports?any?type?of?class,?because?it?does?not?query?
  • ?????*?the?presented?secure?object.?
  • ?????*?
  • ?????*?@param?clazz?the?secure?object?
  • ?????*?
  • ?????*?@return?always?<code>true</code>?
  • ?????*/??
  • ????public?boolean?supports(Class?clazz)?{??
  • ????????return?true;??
  • ????}??
  • ??
  • ????public?int?vote(Authentication?authentication,?Object?object,?ConfigAttributeDefinition?config)?{??
  • ????????int?result?=?ACCESS_ABSTAIN;??
  • ????????Iterator?iter?=?config.getConfigAttributes().iterator();??
  • ????????GrantedAuthority[]?authorities?=?extractAuthorities(authentication);??????????
  • ??
  • ????????while?(iter.hasNext())?{??
  • ????????????ConfigAttribute?attribute?=?(ConfigAttribute)?iter.next();??
  • ??
  • ????????????if?(this.supports(attribute))?{??
  • ????????????????result?=?ACCESS_DENIED;??
  • ??
  • ????????????????//?Attempt?to?find?a?matching?granted?authority??
  • ????????????????for?(int?i?=?0;?i?<?authorities.length;?i++)?{??
  • ????????????????????if?(attribute.getAttribute().equals(authorities[i].getAuthority()))?{??
  • ????????????????????????return?ACCESS_GRANTED;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ??
  • ????????return?result;??
  • ????}??
  • ??????
  • ????GrantedAuthority[]?extractAuthorities(Authentication?authentication)?{??
  • ????????return?authentication.getAuthorities();??
  • ????}??
  • }??


  • 這個類中最重要的代碼就是這句:?

    Java代碼??
  • if?(attribute.getAttribute().equals(authorities[i].getAuthority()))?{??
  • ????????????????????????return?ACCESS_GRANTED;??
  • ????????????????????}??


  • 這句代碼的意思就是把SecureResourceFilterInvocationDefinitionSource傳入的角色名稱與SecurityContextHolder.getContext().getAuthentication()傳入的用戶所擁有的角色的角色名稱相比較,如果相等則通過驗證。?

    在配置文件中還用到了一個投票類AuthenticatedVoter,這個類與RoleVoter屬于同級,RoleVoter用來驗證角色,那AutherticatedVoter又是用來干什么的呢??
    這個類完整代碼:?

    Java代碼??
  • public?class?AuthenticatedVoter?implements?AccessDecisionVoter?{??
  • ????//~?Static?fields/initializers?=====================================================================================??
  • ??
  • ????public?static?final?String?IS_AUTHENTICATED_FULLY?=?"IS_AUTHENTICATED_FULLY";??
  • ????public?static?final?String?IS_AUTHENTICATED_REMEMBERED?=?"IS_AUTHENTICATED_REMEMBERED";??
  • ????public?static?final?String?IS_AUTHENTICATED_ANONYMOUSLY?=?"IS_AUTHENTICATED_ANONYMOUSLY";??
  • ????//~?Instance?fields?================================================================================================??
  • ??
  • ????private?AuthenticationTrustResolver?authenticationTrustResolver?=?new?AuthenticationTrustResolverImpl();??
  • ??
  • ????//~?Methods?========================================================================================================??
  • ??
  • ????private?boolean?isFullyAuthenticated(Authentication?authentication)?{??
  • ????????return?(!authenticationTrustResolver.isAnonymous(authentication)??
  • ????????&&?!authenticationTrustResolver.isRememberMe(authentication));??
  • ????}??
  • ??
  • ????public?void?setAuthenticationTrustResolver(AuthenticationTrustResolver?authenticationTrustResolver)?{??
  • ????????Assert.notNull(authenticationTrustResolver,?"AuthenticationTrustResolver?cannot?be?set?to?null");??
  • ????????this.authenticationTrustResolver?=?authenticationTrustResolver;??
  • ????}??
  • ??
  • ????public?boolean?supports(ConfigAttribute?attribute)?{??
  • ????????if?((attribute.getAttribute()?!=?null)??
  • ????????????&&?(IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())??
  • ????????????||?IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())??
  • ????????????||?IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())))?{??
  • ????????????return?true;??
  • ????????}?else?{??
  • ????????????return?false;??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?This?implementation?supports?any?type?of?class,?because?it?does?not?query?the?presented?secure?object.?
  • ?????*?
  • ?????*?@param?clazz?the?secure?object?
  • ?????*?
  • ?????*?@return?always?<code>true</code>?
  • ?????*/??
  • ????public?boolean?supports(Class?clazz)?{??
  • ????????return?true;??
  • ????}??
  • ??
  • ????public?int?vote(Authentication?authentication,?Object?object,?ConfigAttributeDefinition?config)?{??
  • ????????int?result?=?ACCESS_ABSTAIN;??
  • ????????Iterator?iter?=?config.getConfigAttributes().iterator();??
  • ??
  • ????????while?(iter.hasNext())?{??
  • ????????????ConfigAttribute?attribute?=?(ConfigAttribute)?iter.next();??
  • ??
  • ????????????if?(this.supports(attribute))?{??
  • ????????????????result?=?ACCESS_DENIED;??
  • ??
  • ????????????????if?(IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute()))?{??
  • ????????????????????if?(isFullyAuthenticated(authentication))?{??
  • ????????????????????????return?ACCESS_GRANTED;??
  • ????????????????????}??
  • ????????????????}??
  • ??
  • ????????????????if?(IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute()))?{??
  • ????????????????????if?(authenticationTrustResolver.isRememberMe(authentication)??
  • ????????????????????????||?isFullyAuthenticated(authentication))?{??
  • ????????????????????????return?ACCESS_GRANTED;??
  • ????????????????????}??
  • ????????????????}??
  • ??
  • ????????????????if?(IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute()))?{??
  • ????????????????????if?(authenticationTrustResolver.isAnonymous(authentication)?||?isFullyAuthenticated(authentication)??
  • ????????????????????????||?authenticationTrustResolver.isRememberMe(authentication))?{??
  • ????????????????????????return?ACCESS_GRANTED;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ??
  • ????????return?result;??
  • ????}??
  • }??


  • 作用見下面引用:?
    引用
    AuthenticatedVoter用于判斷ConfigAttribute上是否擁有IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED或IS_AUTHENTICATED_ANONYMOUSLY之類的配置。?
    如果配置為IS_AUTHENTICATED_FULLY,那么只有AuthenticationTrustResolver的isAnonymous()和isRememberMe()都返回false時才能通過驗證。?
    如果配置為IS_AUTHENTICATED_REMEMBERED,那么會在AuthenticationTrustResolver的isAnonymous()返回false時通過驗證。?
    如果配置為IS_AUTHENTICATED_ANONYMOUSLY,就可以在AuthenticationTrustResolver的isAnonymous()和isRememberMe()兩個方法返回任意值時都可以通過驗證。?


    其中上面引用中的ConfigAttribute就是指SecureResourceFilterInvocationDefinitionSource的getAttributes()方法中ConfigAttributeDefinition中的ConfigAttribute,downpour的文章只是傳入了ROLE_USER,ROLE_ADMIN等內容,要想讓AuthenticatedVoter有用武之地,可以傳入?
    IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY中的值。?

    需要注意的是AffirmativeBased中遍歷的投票者是要分先后的,也就是說RoleVoter在AuthenticatedVoter前面的話,會先進行RoleVoter驗證,如果RoleVoter投票未通過,再進行了AuthenticatedVoter投票。?

    這樣spring security的驗證流程就基本清楚了,當然這篇文章也還是有些地方講得不完善,以事有時間再來修改。



    總結

    以上是生活随笔為你收集整理的springSecurity的登录验证的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。