1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      SpringSecurity用戶定義的方法是什么

      這篇文章主要介紹“Spring Security用戶定義的方法是什么”,在日常操作中,相信很多人在Spring Security用戶定義的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring Security用戶定義的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

      網(wǎng)站建設哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、微信小程序開發(fā)、集團企業(yè)網(wǎng)站建設等服務項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了興隆免費建站歡迎大家使用!

      1.絕活一

      先來看如下一段代碼:

      @Configuration
      public class SecurityConfig {
          @Bean
          UserDetailsService us() {
              InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
              manager.createUser(User.withUsername("sang").password("{noop}123").roles("admin").build());
              return manager;
          }

          @Configuration
          @Order(1)
          static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {
              UserDetailsService us1() {
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  manager.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin", "aaa", "bbb").build());
                  return manager;
              }

              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/foo/**")
                          .authorizeRequests()
                          .anyRequest().hasRole("admin")
                          .and()
                          .formLogin()
                          .loginProcessingUrl("/foo/login")
                          .permitAll()
                          .and()
                          .userDetailsService(us1())
                          .csrf().disable();
              }
          }

          @Configuration
          @Order(2)
          static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter {
              UserDetailsService us2() {
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  manager.createUser(User.withUsername("江南一點雨").password("{noop}123").roles("user", "aaa", "bbb").build());
                  return manager;
              }

              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/bar/**")
                          .authorizeRequests()
                          .anyRequest().hasRole("user")
                          .and()
                          .formLogin()
                          .loginProcessingUrl("/bar/login")
                          .permitAll()
                          .and()
                          .csrf().disable()
                          .userDetailsService(us2());
              }
          }
      }

      大家注意,在每一個過濾器鏈中,我都提供了一個 UserDetailsService 實例,然后在 configure(HttpSecurity http) 方法中,配置這個 UserDetailsService 實例。除了每一個過濾器鏈中都配置一個 UserDetailsService 之外,我還提供了一個 UserDetailsService 的 Bean,所以這里前前后后相當于一共有三個用戶,那么我們登錄時候,使用哪個用戶可以登錄成功呢?

      先說結(jié)論:

      • 如果登錄地址是 /foo/login,那么通過 sang 和 javaboy 兩個用戶可以登錄成功。
      • 如果登錄地址是 /bar/login,那么通過 sang 和 江南一點雨 兩個用戶可以登錄成功。

      也就是說,那個全局的,公共的 UserDetailsService 總是有效的,而針對不同過濾器鏈配置的 UserDetailsService 則只針對當前過濾器鏈生效。

      ?  

      這里為了方便,使用了基于內(nèi)存的 UserDetailsService,當然你也可以替換為基于數(shù)據(jù)庫的 UserDetailsService。

      那么接下來我們就來分析一下,為什么是這個樣子?

       

      1.1 源碼分析

       
      1.1.1 全局 AuthenticationManager

      首先大家注意,雖然我定義了兩個過濾器鏈,但是在兩個過濾器鏈的定義中,我都沒有重寫 configure(AuthenticationManagerBuilder auth) 方法,結(jié)合上篇文章,沒有重寫這個方法,就意味著 AuthenticationConfiguration 中提供的全局 AuthenticationManager 是有效的,也就是說,系統(tǒng)默認提供的 AuthenticationManager 將作為其他局部 AuthenticationManager 的 parent。

      那么我們來看下全局的 AuthenticationManager 配置都配了啥?

      public AuthenticationManager getAuthenticationManager() throws Exception {
       if (this.authenticationManagerInitialized) {
        return this.authenticationManager;
       }
       AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
       if (this.buildingAuthenticationManager.getAndSet(true)) {
        return new AuthenticationManagerDelegator(authBuilder);
       }
       for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
        authBuilder.apply(config);
       }
       authenticationManager = authBuilder.build();
       if (authenticationManager == null) {
        authenticationManager = getAuthenticationManagerBean();
       }
       this.authenticationManagerInitialized = true;
       return authenticationManager;
      }
       

      全局的配置中,有一步就是遍歷 globalAuthConfigurers,遍歷全局的 xxxConfigurer,并進行配置。全局的 xxxConfigurer 一共有三個,分別是:

      • EnableGlobalAuthenticationAutowiredConfigurer
      • InitializeUserDetailsBeanManagerConfigurer
      • InitializeAuthenticationProviderBeanManagerConfigurer

      其中 InitializeUserDetailsBeanManagerConfigurer,看名字就是用來配置 UserDetailsService 的,我們來看下:

      @Order(InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER)
      class InitializeUserDetailsBeanManagerConfigurer
        extends GlobalAuthenticationConfigurerAdapter {
       @Override
       public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.apply(new InitializeUserDetailsManagerConfigurer());
       }
       class InitializeUserDetailsManagerConfigurer
         extends GlobalAuthenticationConfigurerAdapter {
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
         if (auth.isConfigured()) {
          return;
         }
         UserDetailsService userDetailsService = getBeanOrNull(
           UserDetailsService.class);
         if (userDetailsService == null) {
          return;
         }
         PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
         UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
         DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
         provider.setUserDetailsService(userDetailsService);
         if (passwordEncoder != null) {
          provider.setPasswordEncoder(passwordEncoder);
         }
         if (passwordManager != null) {
          provider.setUserDetailsPasswordService(passwordManager);
         }
         provider.afterPropertiesSet();
         auth.authenticationProvider(provider);
        }
       }
      }
       

      可以看到,InitializeUserDetailsBeanManagerConfigurer 中定義了內(nèi)部類,在其內(nèi)部類的 configure 方法中,通過 getBeanOrNull 去從容器中查找 UserDetailsService 實例,查找到之后,創(chuàng)建 DaoAuthenticationProvider,并最終配置給 auth 對象。

      這里的 getBeanOrNull 方法從容器中查找到的,實際上就是 Spring 容器中的 Bean,也就是我們一開始配置了 sang 用戶的那個 Bean,這個 Bean 被交給了全局的 AuthenticationManager,也就是所有局部 AuthenticationManager 的 parent。

       
      1.1.2 局部 AuthenticationManager

      所有 HttpSecurity 在構(gòu)建的過程中,都會傳遞一個局部的 AuthenticationManagerBuilder 進來,這個局部的 AuthenticationManagerBuilder 一旦傳進來就存入了共享對象中,以后需要用的時候再從共享對象中取出來,部分代碼如下所示:

      public HttpSecurity(ObjectPostProcessor objectPostProcessor,
        AuthenticationManagerBuilder authenticationBuilder,
        Map, Object> sharedObjects) {
       super(objectPostProcessor);
       Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
       setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
       //省略
      }
      private AuthenticationManagerBuilder getAuthenticationRegistry() {
       return getSharedObject(AuthenticationManagerBuilder.class);
      }
       

      所以,我們在 HttpSecurity 中配置 UserDetailsService,實際上是給這個 AuthenticationManagerBuilder 配置的:

      public HttpSecurity userDetailsService(UserDetailsService userDetailsService)
        throws Exception {
       getAuthenticationRegistry().userDetailsService(userDetailsService);
       return this;
      }
       

      也就是局部 AuthenticationManager。

      至此,整個流程就很清晰了。

      再結(jié)合下面這張圖給大家解釋下:

      Spring Security用戶定義的方法是什么  

      每一個過濾器鏈都會綁定一個自己的 ProviderManager(即 AuthenticationManager 的實現(xiàn)),而每一個 ProviderManager 中都通過 DaoAuthenticationProvider 持有一個 UserDetailsService 對象,你可以簡單理解為一個 ProviderManager 管理了一個 UserDetailsService,當我們開始認證的時候,首先由過濾器鏈所持有的局部 ProviderManager 去認證,要是認證失敗了,則調(diào)用 ProviderManager 的 parent 再去認證,此時就會用到全局 AuthenticationManager 所持有的 UserDetailsService 對象了。

      結(jié)合一開始的案例,例如你的登錄地址是 /foo/login,如果你的登錄用戶是 sang/123,那么先去 HttpSecurity 的局部 ProviderManager 中去驗證,結(jié)果驗證失敗(局部的 ProviderManager 中對應的用戶是 javaboy),此時就會進入局部 ProviderManager 的 parent 中去認證,也就是全局認證,全局的 ProviderManager 中對應的用戶就是 sang 了,此時就認證成功。

       

      2.絕活二

      再次修改 SecurityConfig 的定義,如下:

      @Configuration
      public class SecurityConfig {
          @Bean
          UserDetailsService us() {
              InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
              manager.createUser(User.withUsername("sang").password("{noop}123").roles("admin").build());
              return manager;
          }

          @Configuration
          @Order(1)
          static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {
              UserDetailsService us1() {
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  manager.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin", "aaa", "bbb").build());
                  return manager;
              }

              @Override
              protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  auth.userDetailsService(us1());
              }

              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/foo/**")
                          .authorizeRequests()
                          .anyRequest().hasRole("admin")
                          .and()
                          .formLogin()
                          .loginProcessingUrl("/foo/login")
                          .permitAll()
                          .and()
                          .csrf().disable();
              }
          }

          @Configuration
          @Order(2)
          static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter {
              UserDetailsService us2() {
                  InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                  manager.createUser(User.withUsername("江南一點雨").password("{noop}123").roles("user", "aaa", "bbb").build());
                  return manager;
              }

              @Override
              protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  auth.userDetailsService(us2());
              }

              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/bar/**")
                          .authorizeRequests()
                          .anyRequest().hasRole("user")
                          .and()
                          .formLogin()
                          .loginProcessingUrl("/bar/login")
                          .permitAll()
                          .and()
                          .csrf().disable();
              }
          }
      }
       

      和前面相比,這段代碼的核心變化,就是我重寫了 configure(AuthenticationManagerBuilder auth) 方法,根據(jù)上篇文章的介紹,重寫了該方法之后,全局的 AuthenticationMananger 定義就失效了,也就意味著 sang 這個用戶定義失效了,換言之,無論是 /foo/login 還是 /bar/login,使用 sang/123 現(xiàn)在都無法登錄了。

      在每一個 HttpSecurity 過濾器鏈中,我都重寫了 configure(AuthenticationManagerBuilder auth) 方法,并且重新配置了 UserDetailsService,這個重寫,相當于我在定義 parent 級別的 ProviderManager。而每一個 HttpSecurity 過濾器鏈則不再包含 UserDetailsService。

      當用戶登錄時,先去找到 HttpSecurity 過濾器鏈中的 ProviderManager 去認證,結(jié)果認證失敗,然后再找到 ProviderManager 的 parent 去認證,就成功了。

      到此,關(guān)于“Spring Security用戶定義的方法是什么”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
      分享題目:SpringSecurity用戶定義的方法是什么
      分享地址:http://www.ef60e0e.cn/article/isgpsc.html

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
          1. <ul id="0c1fb"></ul>

            <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
            <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

            商城县| 清水河县| 宝清县| 霸州市| 丁青县| 宁南县| 苏州市| 衡东县| 焉耆| 宜川县| 昭觉县| 历史| 馆陶县| 汉中市| 郑州市| 岳池县| 建湖县| 色达县| 双峰县| 浪卡子县| 方城县| 涿鹿县| 青神县| 金华市| 凌云县| 甘洛县| 二连浩特市| 河东区| 托克逊县| 孟津县| 乐东| 荆州市| 鲁甸县| 图们市| 贵南县| 通化县| 鄂托克前旗| 会昌县| 孟村| 枞阳县| 岳池县|