整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Spring Security 權(quán)限管理的投票器與表決機(jī)制

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

          當(dāng)用戶想訪問 Spring Security 中一個(gè)受保護(hù)的資源時(shí),用戶具備一些角色,該資源的訪問也需要一些角色,在比對(duì)用戶具備的角色和資源需要的角色時(shí),就會(huì)用到投票器和表決機(jī)制。

          當(dāng)用戶想要訪問某一個(gè)資源時(shí),投票器根據(jù)用戶的角色投出贊成或者反對(duì)票,表決方式則根據(jù)投票器的結(jié)果進(jìn)行表決。

          在 Spring Security 中,默認(rèn)提供了三種表決機(jī)制,當(dāng)然,我們也可以不用系統(tǒng)提供的表決機(jī)制和投票器,而是完全自己來定義,這也是可以的。

          本文松哥將和大家重點(diǎn)介紹三種表決機(jī)制和默認(rèn)的投票器。

          1.投票器

          先來看投票器。

          在 Spring Security 中,投票器是由 AccessDecisionVoter 接口來規(guī)范的,我們來看下 AccessDecisionVoter 接口的實(shí)現(xiàn):

          可以看到,投票器的實(shí)現(xiàn)有好多種,我們可以選擇其中一種或多種投票器,也可以自定義投票器,默認(rèn)的投票器是 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. 首先一上來定義了三個(gè)常量,從常量名字中就可以看出每個(gè)常量的含義,1 表示贊成;0 表示棄權(quán);-1 表示拒絕。
          2. 兩個(gè) supports 方法用來判斷投票器是否支持當(dāng)前請(qǐng)求。
          3. vote 則是具體的投票方法。在不同的實(shí)現(xiàn)類中實(shí)現(xiàn)。三個(gè)參數(shù),authentication 表示當(dāng)前登錄主體;object 是一個(gè) ilterInvocation,里邊封裝了當(dāng)前請(qǐng)求;attributes 表示當(dāng)前所訪問的接口所需要的角色集合。

          我們來分別看下幾個(gè)投票器的實(shí)現(xiàn)。

          1.1 RoleVoter

          RoleVoter 主要用來判斷當(dāng)前請(qǐng)求是否具備該接口所需要的角色,我們來看下其 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;
          }
          

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

          另外還有一個(gè)需要注意的地方,就是 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;
           }
          }
          

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

          1.2 RoleHierarchyVoter

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

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

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

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

          1.3 WebExpressionVoter

          這是一個(gè)基于表達(dá)式權(quán)限控制的投票器,松哥后面專門花點(diǎn)時(shí)間和小伙伴們聊一聊基于表達(dá)式的權(quán)限控制,這里我們先不做過多展開,簡(jiǎn)單看下它的 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 的話,這段代碼應(yīng)該說還是很好理解的,不過根據(jù)我的經(jīng)驗(yàn),實(shí)際工作中用到 SpEL 場(chǎng)景雖然有,但是不多,所以可能有很多小伙伴并不了解 SpEL 的用法,這個(gè)需要小伙伴們自行復(fù)習(xí)下,我也給大家推薦一篇還不錯(cuò)的文章:https://www.cnblogs.com/larryzeal/p/5964621.html。

          這里代碼實(shí)際上就是根據(jù)傳入的 attributes 屬性構(gòu)建 weca 對(duì)象,然后根據(jù)傳入的 authentication 參數(shù)構(gòu)建 ctx 對(duì)象,最后調(diào)用 evaluateAsBoolean 方法去判斷權(quán)限是否匹配。

          上面介紹這三個(gè)投票器是我們?cè)趯?shí)際開發(fā)中使用較多的三個(gè)。

          1.4 其他

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

          Jsr250Voter

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

          AuthenticatedVoter

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

          IS_AUTHENTICATED_FULLY 表示當(dāng)前認(rèn)證用戶必須是通過用戶名/密碼的方式認(rèn)證的,通過 RememberMe 的方式認(rèn)證無效。

          IS_AUTHENTICATED_REMEMBERED 表示當(dāng)前登錄用戶必須是通過 RememberMe 的方式完成認(rèn)證的。

          IS_AUTHENTICATED_ANONYMOUSLY 表示當(dāng)前登錄用戶必須是匿名用戶。

          當(dāng)項(xiàng)目引入 RememberMe 并且想?yún)^(qū)分不同的認(rèn)證方式時(shí),可以考慮這個(gè)投票器。

          AbstractAclVoter

          提供編寫域?qū)ο?ACL 選項(xiàng)的幫助方法,沒有綁定到任何特定的 ACL 系統(tǒng)。

          PreInvocationAuthorizationAdviceVoter

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

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

          2.表決機(jī)制

          一個(gè)請(qǐng)求不一定只有一個(gè)投票器,也可能有多個(gè)投票器,所以在投票器的基礎(chǔ)上我們還需要表決機(jī)制。

          表決相關(guān)的類主要是三個(gè):

          • AffirmativeBased
          • ConsensusBased
          • UnanimousBased

          他們的繼承關(guān)系如上圖。

          三個(gè)決策器都會(huì)把項(xiàng)目中的所有投票器調(diào)用一遍,默認(rèn)使用的決策器是 AffirmativeBased。

          三個(gè)決策器的區(qū)別如下:

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

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

          3.在哪里配置

          當(dāng)我們使用基于表達(dá)式的權(quán)限控制時(shí),像下面這樣:

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

          那么默認(rèn)的投票器和決策器是在 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;
          }
          

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

          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();
          

          這里只是給大家一個(gè)演示,正常來說我們是不需要這樣修改的。當(dāng)我們使用不同的權(quán)限配置方式時(shí),會(huì)有自動(dòng)配置對(duì)應(yīng)的投票器和決策器。或者我們手動(dòng)配置投票器和決策器,如果是系統(tǒng)配置好的,大部分情況下并不需要我們修改。

          4.小結(jié)

          本文主要和小伙伴們簡(jiǎn)單分享一下 Spring Security 中的投票器和決策器,關(guān)于授權(quán)的更多知識(shí),松哥下篇文章繼續(xù)和小伙伴們細(xì)聊。

          天是被《即刻電音》相關(guān)熱搜洗版的一天。

          上到節(jié)目主理人,下到主理人粉絲,甚至連主理人的經(jīng)紀(jì)人都沒落下。

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

          到底怎么回事呢?

          原來是《即刻電音》的錄制現(xiàn)場(chǎng)發(fā)生了極大的騷亂。

          來看一個(gè)張藝興粉絲發(fā)來的repo▽

          簡(jiǎn)單總結(jié)一下:

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

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

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

          4.張藝興經(jīng)紀(jì)人上場(chǎng)搶走張藝興話筒,并說大張偉粉絲輸不起就別玩

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

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

          當(dāng)時(shí)因?yàn)橛羞x手對(duì)淘汰的規(guī)則表示不滿,大張偉搬出自己的例子來進(jìn)行說服。

          過程中他一度哽咽地說:“我的心告訴我應(yīng)該退出這個(gè)行業(yè),但我一直都在這個(gè)行業(yè)的原因就是因?yàn)槲覑垡魳贰?strong>我有很多問題,但是也有太多人仗著我喜歡音樂欺負(fù)我。”

          用笑遮掩自己的情緒失控就還挺令人動(dòng)容的▽

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

          咱們也不能只偏聽一方觀點(diǎn),再來看一下大張偉粉絲方面關(guān)于錄制現(xiàn)場(chǎng)的repo▽

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

          但細(xì)節(jié)上進(jìn)行了一些反駁,比如:

          1.大張偉粉絲質(zhì)疑節(jié)目組黑幕是因?yàn)閺牡诙嗛_始就發(fā)現(xiàn)投票器有問題

          2.大張偉情緒激動(dòng)是因?yàn)樗膱F(tuán)隊(duì)面臨團(tuán)滅的風(fēng)險(xiǎn),同時(shí)質(zhì)問導(dǎo)演組:“錢我可以不要了,但你們要有底線。”

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

          4.張藝興確實(shí)大喊開麥被楊天真攔下了,但當(dāng)時(shí)本來就要退場(chǎng)了,所有人的麥都會(huì)被收

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

          不過,讓張藝興粉絲生氣的其中一個(gè)原因還在于大張偉粉絲在節(jié)目現(xiàn)場(chǎng)上升愛豆。

          據(jù)張藝興粉絲描述,當(dāng)時(shí)看張藝興情緒激動(dòng),大張偉粉絲不僅沒有收斂,還冷嘲熱諷罵張藝興犯賤。

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

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

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

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

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

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

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

          于是,其他粉絲只好一而再再而三地進(jìn)行澄清。

          替他們感到心累。

          然而,就在雙方爭(zhēng)得不可開交之時(shí),張藝興粉絲卻開始一條接一條地甩出錄制現(xiàn)場(chǎng)的各種音頻。

          要知道,節(jié)目錄制是不能帶這些電子設(shè)備進(jìn)去的。

          真不愧是經(jīng)驗(yàn)老道的流量粉。

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

          根據(jù)音頻來看,大張偉確實(shí)哽咽了▽

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

          這時(shí),輪到張藝興隊(duì)的隊(duì)員tsunano進(jìn)行發(fā)言。

          他說想給大家講一個(gè)小故事。

          但臺(tái)下卻一直情緒激動(dòng)地在喊“不聽”▽

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

          這些“不聽”、“閉嘴”的抗議聲甚至大到大張偉不得不出面調(diào)節(jié)的程度▽

          而在結(jié)果公布后,節(jié)目組應(yīng)該是有讓主理人進(jìn)到候場(chǎng)區(qū)之類的地方進(jìn)行休息或是調(diào)試。

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

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

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

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

          之前也有人說是大張偉煽動(dòng)了現(xiàn)場(chǎng)的粉絲情緒。

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

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

          當(dāng)時(shí)大張偉并沒有帶麥,算是正常講話的聲音大小,應(yīng)該只有附近一部分粉絲能聽見。

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

          只能說,大家就還挺真情實(shí)感的。

          聽一聽音頻就知道了,現(xiàn)場(chǎng)氛圍真的就跟打群架似的,來一把火隨時(shí)能著...

          面對(duì)如此窘境,主持人只好先cue掌握著最主要投票權(quán)的專業(yè)音樂評(píng)審回應(yīng)黑幕問題▽

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

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

          嗯嗯嗯???

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

          很多比賽就是會(huì)因?yàn)橐黄敝顩Q定命運(yùn)啊,難道不是每一票都很重要嗎???

          不過,從專業(yè)評(píng)審和主持人的兩段話來看,《即刻電音》這個(gè)節(jié)目似乎還真的存在一些問題。

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

          到底咋回事啊...

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

          所以,也怪不得兩邊粉絲會(huì)這樣爆發(fā)。

          連節(jié)目中的另一位主理人尚雯婕都在節(jié)目錄完的第一時(shí)間無語地在微博發(fā)了個(gè)“呵呵”。

          再來說說《即刻電音》這個(gè)節(jié)目。

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

          第一期就因?yàn)檫x手diss大張偉而引發(fā)討論。

          當(dāng)時(shí),選手Anti-General說自己一聽大張偉要來參加節(jié)目,他的第一反應(yīng)就是退賽。

          節(jié)目一播出,Anti-General就因?yàn)檫@番言論被罵很慘。

          隨后,他又在微博發(fā)了長(zhǎng)文進(jìn)行解釋。

          為什么會(huì)在節(jié)目里這樣說?

          一是因?yàn)槌u事件,二是因?yàn)榇髲垈ピ诠?jié)目中所表演的曲目并不能讓他認(rèn)同。

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

          他理解大張偉所承受的精神壓力,但又認(rèn)為這些壓力都是因?yàn)榇髲垈ミ€沒能做出服眾的作品,那大家就只能把以前的事翻出來講。

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

          當(dāng)時(shí)大張偉也有回應(yīng),他說:

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

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

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

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

          大概是因?yàn)槌31徽f抄襲,所以大張偉在《即刻電音》中一直都沖在抓抄襲的第一線。

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

          選手承認(rèn)有借鑒,但并不承認(rèn)抄襲▽

          特邀主理人也認(rèn)同大張偉說的觀點(diǎn)▽

          大張偉則表示,自己之所以會(huì)說這段話,是因?yàn)橛袝r(shí)候大家所認(rèn)為的瑕疵,“天都會(huì)原諒你,但是網(wǎng)友不會(huì)”。

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

          而針對(duì)洗白質(zhì)疑,大張偉自己則說:“我根本沒必要洗白,因?yàn)槲以缇褪遣噬牧恕?/strong>”

          除此之外,圍繞張藝興的主要爭(zhēng)議則是上次讓馮提莫晉級(jí)。

          馮提莫大家應(yīng)該都并不陌生,印象中她跟電音沒扯上過啥關(guān)系。

          但她卻來參加了這檔節(jié)目...

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

          然后給出了這樣的評(píng)價(jià):

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

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

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

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

          “你是一個(gè)很好的歌手,你也是一個(gè)好的制作人,就是呈現(xiàn)出來的東西有點(diǎn)差強(qiáng)人意。”

          到現(xiàn)在為止,張藝興的態(tài)度已經(jīng)很明顯了吧,他并不滿意這個(gè)組合的表演。

          按照這個(gè)走向,他接下來會(huì)很自然地“淘汰”他們才對(duì)。

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

          粉絲們也看不過去了,在評(píng)論里放出了錄制當(dāng)天的“實(shí)情”。

          說是在導(dǎo)演勸說下張藝興才會(huì)讓馮提莫晉級(jí)。

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

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

          熱評(píng)都是“被綁架了你就眨眨眼”...

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

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

          爭(zhēng)議程度怕是跟當(dāng)年的《花少2》都有得一拼了吧?

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

          吃瓜...

          最后一句

          能做的不多,給后期買點(diǎn)防脫洗發(fā)水吧。

          . Spring Security 簡(jiǎn)介

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

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

          • 用戶鑒權(quán)(Authentication), 是指對(duì)用戶身份的鑒權(quán), 驗(yàn)證某個(gè)用戶是否為系統(tǒng)中的合法對(duì)象, 是否能夠訪問對(duì)應(yīng)的系統(tǒng)資源。比如用戶輸入賬戶和密碼登陸系統(tǒng)。
          • 用戶授權(quán)(Authorization),是指授予通過認(rèn)證的用戶指定的系統(tǒng)資源操作權(quán)限, 能否執(zhí)行具體某個(gè)操作。比如用戶能夠訪問操作的菜單,能夠請(qǐng)求的功能接口, 這些都是系統(tǒng)資源。

          Spring Security優(yōu)勢(shì):

          • 靈活性, Spring Security并不局限于Spring MVC,雖然它是基于Spring Framework實(shí)現(xiàn)的,但它并不依賴于Spring MVC,可以獨(dú)立于MVC應(yīng)用在其他Java EE框架之上。
          • 功能強(qiáng)大,Spring Security的安全管制并不只限制于Web請(qǐng)求,除此之外它還可以針對(duì)方法調(diào)用通過AOP的方式進(jìn)行安全管制,甚至可以對(duì)域?qū)ο髮?shí)例(Domain Object Instance)進(jìn)行訪問控制。
          • 安全保護(hù), 防止偽造身份, Spring Security 會(huì)自動(dòng)攔截站點(diǎn)所有狀態(tài)變化的請(qǐng)求(非GET,HEAD,OPTIONS和TRACE的請(qǐng)求),防止跨站請(qǐng)求偽造(CSRF防護(hù)),即防止其他網(wǎng)站或是程序POST等請(qǐng)求本站點(diǎn)。

          如果項(xiàng)目需要安全控制功能,不用自己去實(shí)現(xiàn)一套, 集成Spring Security專業(yè)安全框架是首選, 適用后臺(tái)管理、接口資源管理、微服務(wù)統(tǒng)一鑒權(quán)等場(chǎng)景。

          2. Spring Security設(shè)計(jì)處理機(jī)制

          處理流程圖:


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

          類名

          描述

          AffirmativeBased

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

          ConsensusBased

          多數(shù)票機(jī)制(允許或拒絕),多數(shù)的一方?jīng)Q定了AccessDecisionManager的結(jié)果。平局的投票和空票(全部棄權(quán))的結(jié)果是可配置的

          UnanimousBased

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

          3. Spring Boot 與Spring Security 集成配置

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

          1、創(chuàng)建工程spring-boot-security-integrate

          啟動(dòng)類:

          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 自動(dòng)化配置組件 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-freemarker</artifactId>
                  </dependency>
              </dependencies>

          3、定義一個(gè)外部訪問接口

          1)創(chuàng)建實(shí)體

          定義一個(gè)用戶實(shí)體

          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;
          
          
              /**
               * 創(chuàng)建時(shí)間
               */
              private Date createDate;
          
          }
          

          2)提供Web訪問接口

          提供一個(gè)獲取用戶信息接口

          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"
          

          設(shè)置默認(rèn)的用戶名與密碼為admin。

          5、功能驗(yàn)證

          1) 請(qǐng)求獲取用戶信息接口

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

          沒有鑒權(quán)的情況下, 會(huì)出現(xiàn)登陸界面。

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

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


          4. Spring Security 自定義鑒權(quán)實(shí)現(xiàn)

          4.1 自定義登陸頁面處理

          Spring Security 內(nèi)置會(huì)有一套登陸頁面, 也可以自定修改, 這里通過freemark模板來實(shí)現(xiàn)自定登陸頁面渲染。

          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>自定義系統(tǒng)登陸</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">自定義系統(tǒng)登陸</h2>
                     <input type="text" name="username" class="form-control form-margin-top" placeholder="賬號(hào)" 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靜態(tài)資源文件

          添加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()                //暫時(shí)禁用csrc否則無法提交
                            .httpBasic();
                 }
             }

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

          會(huì)自動(dòng)跳轉(zhuǎn)到自定義的登陸頁面:

          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()                //暫時(shí)禁用csrc否則無法提交
                            .httpBasic();
                 }
                 
             }
             

          通過Spring Security 可以控制, 哪些資源需要受權(quán)限保護(hù), 哪些可以開放訪問。

          • 開放訪問

          /user/userLoginForm 用戶登陸頁面

          /user/doUserLogin 登陸處理地址

          /css/** 靜態(tài)資源文件

          • 權(quán)限保護(hù)

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

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

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

          loginProcessingUrl為登陸請(qǐng)求處理接口地址,可以不用對(duì)其做具體實(shí)現(xiàn),Spring Security 會(huì)做默認(rèn)處理。

          4.3 自定義內(nèi)存模式鑒權(quán)

          1、創(chuàng)建鑒權(quán)用戶對(duì)象:

          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對(duì)象, 將賬號(hào)和密碼信息, 傳遞至父類構(gòu)造方法。

          2、修改SpringSecurityConfiguration配置

          增加:

          @Configuration
          @EnableWebSecurity
          public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
              
              /**
               * 用戶認(rèn)證服務(wù)
               * */
              @Bean
              @Override
              protected UserDetailsService userDetailsService() {
                  //創(chuàng)建基于內(nèi)存用戶管理對(duì)象
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  //自定義權(quán)限
                  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();
              }
              
              ...
          
          }

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

          4.4 自定義登陸成功處理器

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

          @Component
          @Log4j2
          public class SecuritySuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
          
              @Autowired
              private ObjectMapper objectMapper;
          
              /**
               * 認(rèn)證成功處理
               * @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()                //暫時(shí)禁用csrc否則無法提交
                         .httpBasic();
              }

          4.5 自定義登陸失敗處理器

          如果登陸失敗, 也可以通過處理器實(shí)現(xiàn)自定義邏輯。 新建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()));
              }
          }
          

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

          修改自定義配置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()                //暫時(shí)禁用csrc否則無法提交
                         .httpBasic();
              }

          4.6 自定義鑒權(quán)功能驗(yàn)證

          1、驗(yàn)證內(nèi)存模式鑒權(quán)

          內(nèi)存模式我們?cè)O(shè)置的用戶名和密碼為admin/admin123

          默認(rèn)配置文件是admin/admin

          輸入admin/admin123, 成功登陸, 內(nèi)存模式已生效。

          2、登陸成功處理器驗(yàn)證

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

          默認(rèn)是會(huì)跳轉(zhuǎn)到登陸頁面, 如果沒配置登陸成功處理器, 登陸成功后, 會(huì)進(jìn)入上一次訪問頁面

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

          3、登陸失敗處理器驗(yàn)證

          同樣, 問獲取用戶信息接口, http://127.0.0.1:22618/user/getUserInfo, 會(huì)自動(dòng)跳轉(zhuǎn)到登陸頁面。

          采用錯(cuò)誤的用戶密碼, 返回了登陸失敗處理器的結(jié)果。

          5. 總結(jié)

          Spring Security 提供了鑒權(quán)與授權(quán)的功能支持, 這里做了詳細(xì)講解, 如何使用與配置, 并講解了自定義鑒權(quán)處理功能, 實(shí)際業(yè)務(wù)當(dāng)中,并非一層不變, 會(huì)做不同配置修改,比如自定義資源訪問配置, 不同項(xiàng)目有不同的要求, 掌握這些自定義配置, 基本可以覆蓋主要的業(yè)務(wù)場(chǎng)景, 針對(duì)更復(fù)雜的鑒權(quán), 可以采用oauth2做鑒權(quán)處理, 在后續(xù)教程中會(huì)做講解。

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


          主站蜘蛛池模板: 日韩高清一区二区| 无人码一区二区三区视频| 3d动漫精品成人一区二区三| 精品人妻无码一区二区色欲产成人 | 亚洲性色精品一区二区在线| 琪琪see色原网一区二区| 中文字幕人妻第一区| 亚洲av成人一区二区三区 | 国产品无码一区二区三区在线| 久久99精品免费一区二区| 糖心vlog精品一区二区三区| 麻豆国产一区二区在线观看| 国产在线无码一区二区三区视频| 国产在线精品一区二区| 精品久久综合一区二区| 国产成人欧美一区二区三区| 男插女高潮一区二区| 麻豆亚洲av熟女国产一区二 | 亚洲一区二区三区成人网站| 精品人妻码一区二区三区 | 一区二区国产精品| 精品乱子伦一区二区三区高清免费播放| 麻豆一区二区在我观看 | 免费无码一区二区三区蜜桃大| 日韩精品在线一区二区| 日本中文字幕一区二区有码在线| 中文字幕精品一区二区精品| 久久精品国产一区二区三区肥胖 | 一区二区三区精品高清视频免费在线播放 | 中文字幕一区二区精品区| 蜜臀AV一区二区| 国产日韩综合一区二区性色AV| 全国精品一区二区在线观看| 中文字幕在线无码一区| 78成人精品电影在线播放日韩精品电影一区亚洲 | 久久国产三级无码一区二区| 国产一区二区在线看| 国模精品一区二区三区视频| 国产成人精品a视频一区| 亚洲一区二区三区电影| 天堂一区人妻无码|