Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 久久精品视频在线播放,亚洲成人福利视频,国产资源免费

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Spring Security 權限管理的投票器與表決機制

          天咱們來聊一聊 Spring Security 中的表決機制與投票器。

          當用戶想訪問 Spring Security 中一個受保護的資源時,用戶具備一些角色,該資源的訪問也需要一些角色,在比對用戶具備的角色和資源需要的角色時,就會用到投票器和表決機制。

          當用戶想要訪問某一個資源時,投票器根據用戶的角色投出贊成或者反對票,表決方式則根據投票器的結果進行表決。

          在 Spring Security 中,默認提供了三種表決機制,當然,我們也可以不用系統提供的表決機制和投票器,而是完全自己來定義,這也是可以的。

          本文松哥將和大家重點介紹三種表決機制和默認的投票器。

          1.投票器

          先來看投票器。

          在 Spring Security 中,投票器是由 AccessDecisionVoter 接口來規范的,我們來看下 AccessDecisionVoter 接口的實現:

          可以看到,投票器的實現有好多種,我們可以選擇其中一種或多種投票器,也可以自定義投票器,默認的投票器是 WebExpressionVoter。

          我們來看 AccessDecisionVoter 的定義:

          public interface AccessDecisionVoter<S> {
           int ACCESS_GRANTED = 1;
           int ACCESS_ABSTAIN = 0;
           int ACCESS_DENIED = -1;
           boolean supports(ConfigAttribute attribute);
           boolean supports(Class<?> clazz);
           int vote(Authentication authentication, S object,
             Collection<ConfigAttribute> attributes);
          }
          

          我稍微解釋下:

          1. 首先一上來定義了三個常量,從常量名字中就可以看出每個常量的含義,1 表示贊成;0 表示棄權;-1 表示拒絕。
          2. 兩個 supports 方法用來判斷投票器是否支持當前請求。
          3. vote 則是具體的投票方法。在不同的實現類中實現。三個參數,authentication 表示當前登錄主體;object 是一個 ilterInvocation,里邊封裝了當前請求;attributes 表示當前所訪問的接口所需要的角色集合。

          我們來分別看下幾個投票器的實現。

          1.1 RoleVoter

          RoleVoter 主要用來判斷當前請求是否具備該接口所需要的角色,我們來看下其 vote 方法:

          public int vote(Authentication authentication, Object object,
            Collection<ConfigAttribute> attributes) {
           if (authentication == null) {
            return ACCESS_DENIED;
           }
           int result = ACCESS_ABSTAIN;
           Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
           for (ConfigAttribute attribute : attributes) {
            if (this.supports(attribute)) {
             result = ACCESS_DENIED;
             for (GrantedAuthority authority : authorities) {
              if (attribute.getAttribute().equals(authority.getAuthority())) {
               return ACCESS_GRANTED;
              }
             }
            }
           }
           return result;
          }
          

          這個方法的判斷邏輯很簡單,如果當前登錄主體為 null,則直接返回 ACCESS_DENIED 表示拒絕訪問;否則就從當前登錄主體 authentication 中抽取出角色信息,然后和 attributes 進行對比,如果具備 attributes 中所需角色的任意一種,則返回 ACCESS_GRANTED 表示允許訪問。例如 attributes 中的角色為 [a,b,c],當前用戶具備 a,則允許訪問,不需要三種角色同時具備。

          另外還有一個需要注意的地方,就是 RoleVoter 的 supports 方法,我們來看下:

          public class RoleVoter implements AccessDecisionVoter<Object> {
           private String rolePrefix = "ROLE_";
           public String getRolePrefix() {
            return rolePrefix;
           }
           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;
            }
           }
           public boolean supports(Class<?> clazz) {
            return true;
           }
          }
          

          可以看到,這里涉及到了一個 rolePrefix 前綴,這個前綴是 ROLE_,在 supports 方法中,只有主體角色前綴是 ROLE_,這個 supoorts 方法才會返回 true,這個投票器才會生效。

          1.2 RoleHierarchyVoter

          RoleHierarchyVoter 是 RoleVoter 的一個子類,在 RoleVoter 角色判斷的基礎上,引入了角色分層管理,也就是角色繼承,關于角色繼承,小伙伴們可以參考松哥之前的文章(Spring Security 中如何讓上級擁有下級的所有權限?)。

          RoleHierarchyVoter 類的 vote 方法和 RoleVoter 一致,唯一的區別在于 RoleHierarchyVoter 類重寫了 extractAuthorities 方法。

          @Override
          Collection<? extends GrantedAuthority> extractAuthorities(
            Authentication authentication) {
           return roleHierarchy.getReachableGrantedAuthorities(authentication
             .getAuthorities());
          }
          

          角色分層之后,需要通過 getReachableGrantedAuthorities 方法獲取實際具備的角色,具體請參考:Spring Security 中如何讓上級擁有下級的所有權限? 一文。

          1.3 WebExpressionVoter

          這是一個基于表達式權限控制的投票器,松哥后面專門花點時間和小伙伴們聊一聊基于表達式的權限控制,這里我們先不做過多展開,簡單看下它的 vote 方法:

          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;
          }
          

          如果你熟練使用 SpEL 的話,這段代碼應該說還是很好理解的,不過根據我的經驗,實際工作中用到 SpEL 場景雖然有,但是不多,所以可能有很多小伙伴并不了解 SpEL 的用法,這個需要小伙伴們自行復習下,我也給大家推薦一篇還不錯的文章:https://www.cnblogs.com/larryzeal/p/5964621.html。

          這里代碼實際上就是根據傳入的 attributes 屬性構建 weca 對象,然后根據傳入的 authentication 參數構建 ctx 對象,最后調用 evaluateAsBoolean 方法去判斷權限是否匹配。

          上面介紹這三個投票器是我們在實際開發中使用較多的三個。

          1.4 其他

          另外還有幾個比較冷門的投票器,松哥也稍微說下,小伙伴們了解下。

          Jsr250Voter

          處理 Jsr-250 權限注解的投票器,如 @PermitAll,@DenyAll 等。

          AuthenticatedVoter

          AuthenticatedVoter 用于判斷 ConfigAttribute 上是否擁有 IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY 三種角色。

          IS_AUTHENTICATED_FULLY 表示當前認證用戶必須是通過用戶名/密碼的方式認證的,通過 RememberMe 的方式認證無效。

          IS_AUTHENTICATED_REMEMBERED 表示當前登錄用戶必須是通過 RememberMe 的方式完成認證的。

          IS_AUTHENTICATED_ANONYMOUSLY 表示當前登錄用戶必須是匿名用戶。

          當項目引入 RememberMe 并且想區分不同的認證方式時,可以考慮這個投票器。

          AbstractAclVoter

          提供編寫域對象 ACL 選項的幫助方法,沒有綁定到任何特定的 ACL 系統。

          PreInvocationAuthorizationAdviceVoter

          使用 @PreFilter 和 @PreAuthorize 注解處理的權限,通過 PreInvocationAuthorizationAdvice 來授權。

          當然,如果這些投票器不能滿足需求,也可以自定義。

          2.表決機制

          一個請求不一定只有一個投票器,也可能有多個投票器,所以在投票器的基礎上我們還需要表決機制。

          表決相關的類主要是三個:

          • AffirmativeBased
          • ConsensusBased
          • UnanimousBased

          他們的繼承關系如上圖。

          三個決策器都會把項目中的所有投票器調用一遍,默認使用的決策器是 AffirmativeBased。

          三個決策器的區別如下:

          • AffirmativeBased:有一個投票器同意了,就通過。
          • ConsensusBased:多數投票器同意就通過,平局的話,則看 allowIfEqualGrantedDeniedDecisions 參數的取值。
          • UnanimousBased 所有投票器都同意,請求才通過。

          這里的具體判斷邏輯比較簡單,松哥就不貼源碼了,感興趣的小伙伴可以自己看看。

          3.在哪里配置

          當我們使用基于表達式的權限控制時,像下面這樣:

          http.authorizeRequests()
                  .antMatchers("/admin/**").hasRole("admin")
                  .antMatchers("/user/**").hasRole("user")
                  .anyRequest().fullyAuthenticated()
          

          那么默認的投票器和決策器是在 AbstractInterceptUrlConfigurer#createDefaultAccessDecisionManager 方法中配置的:

          private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
           AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
           return postProcess(result);
          }
          List<AccessDecisionVoter<?>> getDecisionVoters(H http) {
           List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
           WebExpressionVoter expressionVoter = new WebExpressionVoter();
           expressionVoter.setExpressionHandler(getExpressionHandler(http));
           decisionVoters.add(expressionVoter);
           return decisionVoters;
          }
          

          這里就可以看到默認的決策器和投票器,并且決策器 AffirmativeBased 對象創建好之后,還調用 postProcess 方法注冊到 Spring 容器中去了,結合松哥本系列前面的文章,大家知道,如果我們想要修改該對象就非常容易了:

          http.authorizeRequests()
                  .antMatchers("/admin/**").hasRole("admin")
                  .antMatchers("/user/**").hasRole("user")
                  .anyRequest().fullyAuthenticated()
                  .withObjectPostProcessor(new ObjectPostProcessor<AffirmativeBased>() {
                      @Override
                      public <O extends AffirmativeBased> O postProcess(O object) {
                          List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
                          decisionVoters.add(new RoleHierarchyVoter(roleHierarchy()));
                          AffirmativeBased affirmativeBased = new AffirmativeBased(decisionVoters);
                          return (O) affirmativeBased;
                      }
                  })
                  .and()
                  .csrf()
                  .disable();
          

          這里只是給大家一個演示,正常來說我們是不需要這樣修改的。當我們使用不同的權限配置方式時,會有自動配置對應的投票器和決策器。或者我們手動配置投票器和決策器,如果是系統配置好的,大部分情況下并不需要我們修改。

          4.小結

          本文主要和小伙伴們簡單分享一下 Spring Security 中的投票器和決策器,關于授權的更多知識,松哥下篇文章繼續和小伙伴們細聊。

          天是被《即刻電音》相關熱搜洗版的一天。

          上到節目主理人,下到主理人粉絲,甚至連主理人的經紀人都沒落下。

          可能是節目開播以來喜提熱搜最多的一次。

          到底怎么回事呢?

          原來是《即刻電音》的錄制現場發生了極大的騷亂。

          來看一個張藝興粉絲發來的repo▽

          簡單總結一下:

          1.大張偉粉絲覺得節目投票有問題,一直在喊“黑幕”

          2.大張偉為保隊員又一次打起了感情牌

          3.張藝興想說話卻發現話筒沒聲,憤怒地喊“開麥”和“宇宙(張藝興隊名)就是diao”

          4.張藝興經紀人上場搶走張藝興話筒,并說大張偉粉絲輸不起就別玩

          插播一條,給沒看過《即刻電音》的朋友們補補課。

          張藝興粉絲控訴的打感情牌其實是指大張偉在節目中哭訴的事。

          當時因為有選手對淘汰的規則表示不滿,大張偉搬出自己的例子來進行說服。

          過程中他一度哽咽地說:“我的心告訴我應該退出這個行業,但我一直都在這個行業的原因就是因為我愛音樂。我有很多問題,但是也有太多人仗著我喜歡音樂欺負我。

          用笑遮掩自己的情緒失控就還挺令人動容的▽

          OK,補完課再回到兩家粉絲撕X的事。

          咱們也不能只偏聽一方觀點,再來看一下大張偉粉絲方面關于錄制現場的repo▽

          過程上的描述和張藝興粉絲那邊的說法基本相同。

          但細節上進行了一些反駁,比如:

          1.大張偉粉絲質疑節目組黑幕是因為從第二輪開始就發現投票器有問題

          2.大張偉情緒激動是因為他的團隊面臨團滅的風險,同時質問導演組:“錢我可以不要了,但你們要有底線。”

          3.大張偉粉絲罵節目組的話被路過的張藝興聽到了,并回頭問大張偉粉絲“誰罵我”

          4.張藝興確實大喊開麥被楊天真攔下了,但當時本來就要退場了,所有人的麥都會被收

          也是個公說公有理,婆說婆有理的“羅生門”。

          不過,讓張藝興粉絲生氣的其中一個原因還在于大張偉粉絲在節目現場上升愛豆。

          據張藝興粉絲描述,當時看張藝興情緒激動,大張偉粉絲不僅沒有收斂,還冷嘲熱諷罵張藝興犯賤。

          說:“見過撿錢的,見過撿東西的,沒見過撿罵的。”

          但大張偉粉絲則說,他們壓根沒罵張藝興,罵的是這個XX的世界,結果恰好被路過的張藝興聽到。

          由此還衍生出了一個關于張藝興從大張偉粉絲全世界路過的段子...

          更抓馬的部分在于,兩方粉絲都說是第一次見自家愛豆這么生氣。

          粉絲的賣慘邏輯就真的都很相似。

          大張偉粉絲還痛心疾首稱:“我第一次見大張偉當眾給自己一個耳光,這要怎么才能下得去手?”

          本來張藝興粉絲就一直在斥責大張偉賣慘了,這么一說不是在給對家送錘送人頭嗎...

          于是,其他粉絲只好一而再再而三地進行澄清。

          替他們感到心累。

          然而,就在雙方爭得不可開交之時,張藝興粉絲卻開始一條接一條地甩出錄制現場的各種音頻。

          要知道,節目錄制是不能帶這些電子設備進去的。

          真不愧是經驗老道的流量粉。

          M@https://v.youku.com/v_show/id_XMzk4OTUxNTQzNg==.html@M

          根據音頻來看,大張偉確實哽咽了▽

          大張偉發言完畢后,他的粉絲用很大的聲音喊“黑幕”▽

          這時,輪到張藝興隊的隊員tsunano進行發言。

          他說想給大家講一個小故事。

          但臺下卻一直情緒激動地在喊“不聽”▽

          tsunano試圖將故事繼續講下去,背景音卻全是讓他閉嘴的聲音▽

          這些“不聽”、“閉嘴”的抗議聲甚至大到大張偉不得不出面調節的程度▽

          而在結果公布后,節目組應該是有讓主理人進到候場區之類的地方進行休息或是調試。

          只聽到錄制重新開始,導演讓主理人回到各自的位置。

          就在這時,張藝興突然大喊了幾聲開麥。

          開麥后,就有了他感慨“wow”。

          緊接著就是repo種所說的張藝興歇斯底里的那句“宇宙隊就是最diao的”。

          之前也有人說是大張偉煽動了現場的粉絲情緒。

          在被曝光的另一段錄音當中,有粉絲錄到休息期間,大張偉的確帶著情緒對張藝興粉絲 說了“你們牛逼”。

          但橘子君聽完音頻覺得倒也不像一些repo當中說的那樣是朝張藝興粉絲喊話。

          當時大張偉并沒有帶麥,算是正常講話的聲音大小,應該只有附近一部分粉絲能聽見。

          萬萬沒想到,錄個節目竟然能錄到兩位在娛樂圈摸爬滾打多年的藝人全都情緒失控...

          只能說,大家就還挺真情實感的。

          聽一聽音頻就知道了,現場氛圍真的就跟打群架似的,來一把火隨時能著...

          面對如此窘境,主持人只好先cue掌握著最主要投票權的專業音樂評審回應黑幕問題▽

          看觀眾情緒依然未得到任和平復,主持人又出面了。

          他說:“這個節目沒有黑幕,也沒必要有黑幕。你覺得你投票器壞了那一票就能夠讓整個節目的結果有所改變嗎?你覺得所有你們投票器壞了就針對你們了嗎?”

          嗯嗯嗯???

          主持人不應該是起到安撫作用嗎,怎么所說的話還這么具有煽動性呢???

          很多比賽就是會因為一票之差決定命運啊,難道不是每一票都很重要嗎???

          不過,從專業評審和主持人的兩段話來看,《即刻電音》這個節目似乎還真的存在一些問題。

          投票器壞掉也就算了,專業評審竟然說自己沒有完整看到選手的演出???

          到底咋回事啊...

          不是說好的公平公正嗎[捂臉]...

          所以,也怪不得兩邊粉絲會這樣爆發。

          連節目中的另一位主理人尚雯婕都在節目錄完的第一時間無語地在微博發了個“呵呵”。

          再來說說《即刻電音》這個節目。

          別看它電音的題材小眾,但每期的話題還真不比爆款節目來得少。

          第一期就因為選手diss大張偉而引發討論。

          當時,選手Anti-General說自己一聽大張偉要來參加節目,他的第一反應就是退賽。

          節目一播出,Anti-General就因為這番言論被罵很慘。

          隨后,他又在微博發了長文進行解釋。

          為什么會在節目里這樣說?

          一是因為抄襲事件,二是因為大張偉在節目中所表演的曲目并不能讓他認同。

          雖然大張偉在節目中的一些專業表現讓他的印象有所改觀,但他還是認為大張偉在用自己做不到的事要求別人。

          他理解大張偉所承受的精神壓力,但又認為這些壓力都是因為大張偉還沒能做出服眾的作品,那大家就只能把以前的事翻出來講。

          最后,Anti-General還很嗆地放話:至于大老師你這次能不能洗白,我們拭目以待。

          當時大張偉也有回應,他說:

          “一個常年在做音樂的人,即便不善言表,答起這個‘自己’的問題也會滔滔不絕。”

          “我音樂中的自己就是DM48的游樂園,就是陽光彩虹小白馬,就是必須熱血有趣又可愛。”

          算是解答了Anti-General說他“用自己做不到的事要求別人”的這部分▽

          但選手所提出的洗白質疑依然依然是目前《即刻電音》為人詬病的問題之一。

          大概是因為常常被說抄襲,所以大張偉在《即刻電音》中一直都沖在抓抄襲的第一線。

          選手表演完,他立刻就說跟某樂隊的音樂有些相似▽

          選手承認有借鑒,但并不承認抄襲▽

          特邀主理人也認同大張偉說的觀點▽

          大張偉則表示,自己之所以會說這段話,是因為有時候大家所認為的瑕疵,“天都會原諒你,但是網友不會”。

          再加上開頭我們放過的那段大張偉哭訴截圖,理所當然有不少人會質疑這節目是在給大張偉洗白。

          而針對洗白質疑,大張偉自己則說:“我根本沒必要洗白,因為我早就是彩色的了。

          除此之外,圍繞張藝興的主要爭議則是上次讓馮提莫晉級。

          馮提莫大家應該都并不陌生,印象中她跟電音沒扯上過啥關系。

          但她卻來參加了這檔節目...

          張藝興看完表演后很為難,他先是做了這樣一個雙手抱頭的動作,說了一句“嘶...喔...這個......這個怎么說呢”▽

          然后給出了這樣的評價:

          “你們選的是未來感,沒有讓我覺得很未來啊。”

          這時候和馮提莫一起合作的KK張站出來幫馮提莫講話,說“想要幫她制作和改編歌曲,所以在編曲上用了大量未來的聲音設計......”

          藝興終于聽不下去了,舉手打斷:

          “等一下,對不起打斷你一下,就是我覺得就很普通,一般的電子舞曲的歌曲就是這樣的,我沒有覺得有什么很未來的東西。”

          “你是一個很好的歌手,你也是一個好的制作人,就是呈現出來的東西有點差強人意。”

          到現在為止,張藝興的態度已經很明顯了吧,他并不滿意這個組合的表演。

          按照這個走向,他接下來會很自然地“淘汰”他們才對。

          然而最終的結果是,他給了“推薦”(滿臉寫著開心)▽

          粉絲們也看不過去了,在評論里放出了錄制當天的“實情”。

          說是在導演勸說下張藝興才會讓馮提莫晉級。

          但張藝興自己則說“是我做的決定,導演組沒有逼我”。

          但也并沒有多少人相信就是了。

          熱評都是“被綁架了你就眨眨眼”...

          -------------------------

          到目前為止《即刻電音》一共才播了5期,爭議話題就已經有前面說的這么多了。

          爭議程度怕是跟當年的《花少2》都有得一拼了吧?

          還不知道最新錄制的這一期已經亂到這種程度后期要怎么剪。

          吃瓜...

          最后一句

          能做的不多,給后期買點防脫洗發水吧。

          . Spring Security 簡介

          Spring Security 是一種基于 Spring AOP 和 Servlet 過濾器的安全框架。原名Acegi Security,最早于2003年起源于Spring社區。 2007年末正式歸為Spring Framework的正式子項目,并改名為Spring Security 。此后, Spring Security有了長遠發展,現已成為一款基于Spring Framework的廣泛應用的安全框架,主要為應用服務提供用戶認證(Authentication)和用戶授權(Authorization)功能。詳情可參考Spring Security 官方文檔。

          Spring Security 針對安全方面的兩大難題, 鑒權(Authentication)和授權(Authorization)提供了靈活強大的解決方案。

          • 用戶鑒權(Authentication), 是指對用戶身份的鑒權, 驗證某個用戶是否為系統中的合法對象, 是否能夠訪問對應的系統資源。比如用戶輸入賬戶和密碼登陸系統。
          • 用戶授權(Authorization),是指授予通過認證的用戶指定的系統資源操作權限, 能否執行具體某個操作。比如用戶能夠訪問操作的菜單,能夠請求的功能接口, 這些都是系統資源。

          Spring Security優勢:

          • 靈活性, Spring Security并不局限于Spring MVC,雖然它是基于Spring Framework實現的,但它并不依賴于Spring MVC,可以獨立于MVC應用在其他Java EE框架之上。
          • 功能強大,Spring Security的安全管制并不只限制于Web請求,除此之外它還可以針對方法調用通過AOP的方式進行安全管制,甚至可以對域對象實例(Domain Object Instance)進行訪問控制。
          • 安全保護, 防止偽造身份, Spring Security 會自動攔截站點所有狀態變化的請求(非GET,HEAD,OPTIONS和TRACE的請求),防止跨站請求偽造(CSRF防護),即防止其他網站或是程序POST等請求本站點。

          如果項目需要安全控制功能,不用自己去實現一套, 集成Spring Security專業安全框架是首選, 適用后臺管理、接口資源管理、微服務統一鑒權等場景。

          2. Spring Security設計處理機制

          處理流程圖:


          • 客戶端發起一個請求,進入 Security 過濾器鏈。
          • 當到 LogoutFilter 的時候判斷是否是登出路徑,如果是登出路徑則到 logoutHandler ,如果登出成功則到 logoutSuccessHandler 登出成功處理,如果登出失敗則由 ExceptionTranslationFilter ;如果不是登出路徑則直接進入下一個過濾器。
          • 當到 UsernamePasswordAuthenticationFilter 的時候判斷是否為登錄路徑,如果是,則進入該過濾器進行登錄操作,如果登錄失敗則到 AuthenticationFailureHandler 登錄失敗處理器處理,如果登錄成功則到 AuthenticationSuccessHandler 登錄成功處理器處理,如果不是登錄請求則不進入該過濾器。
          • 當到 FilterSecurityInterceptor 的時候會拿到 uri ,根據 uri 去找對應的鑒權管理器,鑒權管理器做鑒權工作,鑒權成功則到 Controller 層否則到 AccessDeniedHandler 鑒權失敗處理器處理。
          • 投票機制, 三種表決方式, 默認采用一票制(AffirmativeBased

          類名

          描述

          AffirmativeBased

          只要有一個投票器允許訪問, 請求立刻允許放行, 不管之前存在拒絕的決定

          ConsensusBased

          多數票機制(允許或拒絕),多數的一方決定了AccessDecisionManager的結果。平局的投票和空票(全部棄權)的結果是可配置的

          UnanimousBased

          所有的投票器必須全部是允許的, 否則訪問將被拒絕

          3. Spring Boot 與Spring Security 集成配置

          Spring Boot 與Spring Security 集成, 包含一般集成用法, 還包括自定義用戶登陸頁面使用, 自定義內存模式驗證, 以及自定義登陸成功與失敗邏輯處理。

          1、創建工程spring-boot-security-integrate

          啟動類:

          com.mirson.spring.boot.security.integrate.startup.SecurityIntegrateApplication

          @SpringBootApplication
          @ComponentScan(basePackages = {"com.mirson"})
          public class SecurityIntegrateApplication {
          
              public static void main(String[] args) {
                  SpringApplication.run(SecurityIntegrateApplication.class, args);
              }
          }
          

          2、MAVEN依賴

          <dependencies>
                  <!-- Spring Boot Security 安全依賴組件 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-security</artifactId>
                  </dependency>
                  <!-- Spring Boot Thymeleaf 模板依賴組件 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-thymeleaf</artifactId>
                  </dependency>
                  <!-- Spring Boot Web 依賴組件 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
                  <!--Spring boot freemarker 自動化配置組件 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-freemarker</artifactId>
                  </dependency>
              </dependencies>

          3、定義一個外部訪問接口

          1)創建實體

          定義一個用戶實體

          com.mirson.spring.boot.security.integrate.po.User

          @Data
          public class User {
          
              /**
               * ID
               */
              private Integer id;
          
              /**
               * 用戶名稱
               */
              private String name;
          
              /**
               * 年齡
               */
              private String age;
          
              /**
               * 省份
               */
              private String province;
          
          
              /**
               * 創建時間
               */
              private Date createDate;
          
          }
          

          2)提供Web訪問接口

          提供一個獲取用戶信息接口

          com.mirson.spring.boot.security.integrate.controller.UserController

          @RestController
          @RequestMapping("/user")
          @Log4j2
          public class UserController {
          
              @GetMapping("/getUserInfo")
              @ResponseBody
              public User getUserInfo() {
                  User user = new User();
                  user.setId(0);
                  user.setAge("21");
                  user.setName("user1");
                  user.setCreateDate(new Date());
                  return user;
              }
          
          }
          

          4、工程配置

          server:
            port: 22618
          spring:
            application:
              name: security-integrate
          
            # security 安全配置
            security:
              user:
                name: "admin"
                password: "admin"
          

          設置默認的用戶名與密碼為admin。

          5、功能驗證

          1) 請求獲取用戶信息接口

          訪問接口: http://127.0.0.1:22618/getUserInfo

          沒有鑒權的情況下, 會出現登陸界面。

          2)輸入用戶信息admin/admin, 再次請求獲取用戶信息接口

          正確輸入用戶信息后, 可以正常訪問用戶信息接口。


          4. Spring Security 自定義鑒權實現

          4.1 自定義登陸頁面處理

          Spring Security 內置會有一套登陸頁面, 也可以自定修改, 這里通過freemark模板來實現自定登陸頁面渲染。

          application.yml增加配置:

             # freemarker 模板配置
               freemarker:
                 allow-request-override: false
                 allow-session-override: false
                 cache: true
                 charset: UTF-8
                 check-template-location: true
                 content-type: text/html
                 enabled: true
                 expose-request-attributes: false
                 expose-session-attributes: false
                 expose-spring-macro-helpers: true
                 prefer-file-system-access: true
                 suffix: .ftl
                 template-loader-path: classpath:/templates/
             

          增加freemark模板文件:

             <!DOCTYPE html>
             <html lang="en">
               <head>
                 <meta charset="utf-8">
                 <meta http-equiv="X-UA-Compatible" content="IE=edge">
                 <meta name="viewport" content="width=device-width, initial-scale=1">
                 <meta name="description" content="">
                 <meta name="author" content="">
             
                 <title>自定義系統登陸</title>
             
                 <link href="/css/bootstrap.min.css" rel="stylesheet">
                 <link href="/css/signin.css" rel="stylesheet">
               </head>
             
               <body>
                 <div class="container form-margin-top">
                   <form class="form-signin" action="/user/doUserLogin" method="post">
                     <h2 class="form-signin-heading" align="center">自定義系統登陸</h2>
                     <input type="text" name="username" class="form-control form-margin-top" placeholder="賬號" required autofocus>
                     <input type="password" name="password" class="form-control" placeholder="密碼" required>
                     <button class="btn btn-lg btn-primary btn-block" type="submit">sign in</button>
                   </form>
                 </div>
                 <footer>
                   <p>support by: mirson</p>
                 </footer>
               </body>
             </html>
             

          添加CSS靜態資源文件

          添加JAVA CONFIG配置:

          com.mirson.spring.boot.security.integrate.config.SpringSecurityConfiguration

             @Configuration
             @EnableWebSecurity
             public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
                 @Override
                 protected void configure(HttpSecurity http) throws Exception {
                    http
                            .authorizeRequests()
                            .antMatchers("/user/userLoginForm",
                                    "/css/**").permitAll()
                            .antMatchers("/user/getUserInfo").authenticated() 
                            .and()
                            .formLogin()
                            .loginPage("/user/userLoginForm")    //自定義登錄頁面             
                            .permitAll()            //允許所有人訪問該路由
                            .and()
                            .csrf()
                            .disable()                //暫時禁用csrc否則無法提交
                            .httpBasic();
                 }
             }

          重啟, 訪問接口: http://127.0.0.1:22618/user/getUserInfo

          會自動跳轉到自定義的登陸頁面:

          4.2 自定義資源訪問配置

          修改com.mirson.spring.boot.security.integrate.config.SpringSecurityConfiguration配置:

             @Configuration
             @EnableWebSecurity
             public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
                 
                 @Override
                 protected void configure(HttpSecurity http) throws Exception {
                    http
                            .authorizeRequests()
                            .antMatchers("/user/doUserLogin", "/user/userLoginForm",
                                    "/css/**").permitAll()
                            .antMatchers("/user/getUserInfo").authenticated() //hasRole("ADMIN")
                            .and()
                            .formLogin()
                            .loginPage("/user/userLoginForm")    //自定義登錄頁面
                            .loginProcessingUrl("/user/doUserLogin") // 自定義登陸處理地址
                            .permitAll()            //允許所有人訪問該路由
                            .and()
                            .csrf()
                            .disable()                //暫時禁用csrc否則無法提交
                            .httpBasic();
                 }
                 
             }
             

          通過Spring Security 可以控制, 哪些資源需要受權限保護, 哪些可以開放訪問。

          • 開放訪問

          /user/userLoginForm 用戶登陸頁面

          /user/doUserLogin 登陸處理地址

          /css/** 靜態資源文件

          • 權限保護

          /user/getUserInfo 獲取用戶信息接口

          可以指定Role角色權限, 不指定, 只要登陸即擁有訪問權限。

          loginPage指定/user/userLoginForm為自定義登陸頁面;

          loginProcessingUrl為登陸請求處理接口地址,可以不用對其做具體實現,Spring Security 會做默認處理。

          4.3 自定義內存模式鑒權

          1、創建鑒權用戶對象:

          com.mirson.spring.boot.security.integrate.po.OAuthUser

          
          @Data
          public class OAuthUser extends User {
          
              public OAuthUser(String account, String password){
          
                  super(account, password, true, true, true, true, Collections.EMPTY_SET);
              }
          
          }
          

          繼承的是Spring Security 的User對象, 將賬號和密碼信息, 傳遞至父類構造方法。

          2、修改SpringSecurityConfiguration配置

          增加:

          @Configuration
          @EnableWebSecurity
          public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
              
              /**
               * 用戶認證服務
               * */
              @Bean
              @Override
              protected UserDetailsService userDetailsService() {
                  //創建基于內存用戶管理對象
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  //自定義權限
                  Collection<GrantedAuthority> adminAuth = new ArrayList<>();
                  adminAuth.add(new SimpleGrantedAuthority("ADMIN"));
                  //自定義用戶
                  OAuthUser oAuthUser = new OAuthUser("admin", "admin123");
                  manager.createUser(oAuthUser);
                  return manager;
              }
              
              /**
               * 配置密碼編碼器, 不需加密
               * @return
               */
              @Bean
              public static NoOpPasswordEncoder passwordEncoder() {
                  return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
              }
              
              ...
          
          }

          采用內存模式管理用戶對象InMemoryUserDetailsManager, 自定義認證用戶名和密碼, 分別為admin,admin123。 需要配置密碼編碼器, 可以支持自定義密碼加密方式, 這里不需加密, 配置NoOpPasswordEncoder。

          4.4 自定義登陸成功處理器

          Spring Security 提供了接口, 登陸成功, 可以通過處理器實現自定義邏輯。 新建com.mirson.spring.boot.security.integrate.handler.SecuritySuccessHandler

          @Component
          @Log4j2
          public class SecuritySuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
          
              @Autowired
              private ObjectMapper objectMapper;
          
              /**
               * 認證成功處理
               * @param request
               * @param response
               * @param authentication
               * @throws IOException
               * @throws ServletException
               */
              @Override
              public void onAuthenticationSuccess(HttpServletRequest request,
                                                  HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
          
                  log.info("Process in SecuritySuccessHandler ==> login success.");
                  response.setContentType("application/json;charset=UTF-8");
                  response.getWriter().write(objectMapper.writeValueAsString(authentication));
              }
          }

          這里通過自定義登陸成功處理器, 將登陸成功的信息返回客戶端。

          將處理器加入到自定義配置SpringSecurityConfiguration中:

          	@Override
              protected void configure(HttpSecurity http) throws Exception {
                 http
                         .authorizeRequests()
                         .antMatchers("/user/doUserLogin", "/user/userLoginForm",
                                 "/css/**").permitAll()
                         .antMatchers("/user/getUserInfo").authenticated() //hasRole("ADMIN")
                         .and()
                         .formLogin()
                         .loginPage("/user/userLoginForm")    //自定義登錄頁面
                         .loginProcessingUrl("/user/doUserLogin") // 自定義登陸處理地址
                         .successHandler(securitySuccessHandler)  // 自定義登陸成功處理器
                         .permitAll()            //允許所有人訪問該路由
                         .and()
                         .csrf()
                         .disable()                //暫時禁用csrc否則無法提交
                         .httpBasic();
              }

          4.5 自定義登陸失敗處理器

          如果登陸失敗, 也可以通過處理器實現自定義邏輯。 新建com.mirson.spring.boot.security.integrate.handler.SecurityFailureHandler

          @Component
          @Log4j2
          public class SecurityFailureHandler extends SimpleUrlAuthenticationFailureHandler {
          
              @Autowired
              private ObjectMapper objectMapper;
          
              @Override
              public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                                  AuthenticationException exception) throws IOException, ServletException {
          
                  log.info("Process in SecurityFailureHandler ==> login failure.");
                  response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                  response.setContentType("application/json;charset=UTF-8");
                  response.getWriter().write(objectMapper.writeValueAsString(exception.getMessage()));
              }
          }
          

          將登陸失敗的錯誤信息, 返回給客戶端。

          修改自定義配置SpringSecurityConfiguration:

          @Override
              protected void configure(HttpSecurity http) throws Exception {
                 http
                         .authorizeRequests()
                         .antMatchers("/user/doUserLogin", "/user/userLoginForm",
                                 "/css/**").permitAll()
                         .antMatchers("/user/getUserInfo").authenticated() //hasRole("ADMIN")
                         .and()
                         .formLogin()
                         .loginPage("/user/userLoginForm")    //自定義登錄頁面
                         .loginProcessingUrl("/user/doUserLogin") // 自定義登陸處理地址
                         .successHandler(securitySuccessHandler)  // 自定義登陸成功處理器
                         .failureHandler(securityFailureHandler)  // 自定義登陸失敗處理器
                         .permitAll()            //允許所有人訪問該路由
                         .and()
                         .csrf()
                         .disable()                //暫時禁用csrc否則無法提交
                         .httpBasic();
              }

          4.6 自定義鑒權功能驗證

          1、驗證內存模式鑒權

          內存模式我們設置的用戶名和密碼為admin/admin123

          默認配置文件是admin/admin

          輸入admin/admin123, 成功登陸, 內存模式已生效。

          2、登陸成功處理器驗證

          重啟服務, 訪問獲取用戶信息接口, http://127.0.0.1:22618/user/getUserInfo

          默認是會跳轉到登陸頁面, 如果沒配置登陸成功處理器, 登陸成功后, 會進入上一次訪問頁面

          可以看到, 登陸成功后, 并沒有跳轉到上一次訪問的用戶信息接口, 而是返回了登陸成功處理器的結果。

          3、登陸失敗處理器驗證

          同樣, 問獲取用戶信息接口, http://127.0.0.1:22618/user/getUserInfo, 會自動跳轉到登陸頁面。

          采用錯誤的用戶密碼, 返回了登陸失敗處理器的結果。

          5. 總結

          Spring Security 提供了鑒權與授權的功能支持, 這里做了詳細講解, 如何使用與配置, 并講解了自定義鑒權處理功能, 實際業務當中,并非一層不變, 會做不同配置修改,比如自定義資源訪問配置, 不同項目有不同的要求, 掌握這些自定義配置, 基本可以覆蓋主要的業務場景, 針對更復雜的鑒權, 可以采用oauth2做鑒權處理, 在后續教程中會做講解。

          教程源碼下載地址: https://download.csdn.net/download/hxx688/86400104


          主站蜘蛛池模板: 天堂不卡一区二区视频在线观看| 国产婷婷一区二区三区| 一区二区三区电影网| ...91久久精品一区二区三区| 国产伦一区二区三区免费| 无码少妇精品一区二区免费动态| 国产视频福利一区| 无码国产精品久久一区免费| 精品国产日产一区二区三区| 一区二区三区在线观看视频 | 色一情一乱一伦一区二区三区 | 色精品一区二区三区| 人妻体体内射精一区二区| 免费精品一区二区三区第35| 国产精品一区在线观看你懂的| 国产a久久精品一区二区三区| 精品国产免费观看一区 | 国产主播一区二区三区在线观看| 国产精品一区视频| 亚洲熟女www一区二区三区| 亚洲日本久久一区二区va| 亚洲日韩中文字幕一区| 亚洲精品日韩一区二区小说| 久久无码AV一区二区三区| av无码免费一区二区三区| 亚洲AV无码一区二区三区牛牛| 国产福利视频一区二区| 亚洲精品无码一区二区| 无码人妻aⅴ一区二区三区有奶水 人妻夜夜爽天天爽一区 | 国产日韩视频一区| 视频一区视频二区制服丝袜| 一区二区视频在线免费观看| 日韩动漫av在线播放一区| 99久久国产精品免费一区二区| 秋霞午夜一区二区| 国产精品日韩欧美一区二区三区| 日本在线电影一区二区三区| 亚洲乱码国产一区网址| 免费一区二区三区| 日本无卡码免费一区二区三区| 国产美女av在线一区|