spring security之httpSecurity使用示例

weixin_34391854發表於2015-06-03

httpSecurity

   類似於spring security的xml配置檔案名稱空間配置中的<http>元素。它允許對特定的http請求基於安全考慮進行配置。預設情況下,適用於所有的請求,但可以使用requestMatcher(RequestMatcher)或者其它相似的方法進行限制。

使用示例:

最基本的基於表單的配置如下。該配置將所有的url訪問許可權設定為角色名稱為"ROLE_USER".同時也定義了記憶體認證模式:使用使用者名稱"user"和密碼“password”,角色"ROLE_USER"來認證。

  @Configuration
  @EnableWebSecurity
  public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
 
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
              .authorizeRequests()
                  .antMatchers("/").hasRole("USER")
                  .and()
              .formLogin();
      }
 
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth
               .inMemoryAuthentication()
                    .withUser("user")
                         .password("password")
                         .roles("USER");
      }
  }

 配置基於openId的認證方式

 basic示例,不使用attribute exchange

             @Configuration
      @EnableWebSecurity
      public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .openidLogin()
                      .permitAll();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth
                      .inMemoryAuthentication()
                          // the username must match the OpenID of the user you are
                          // logging in with
                          .withUser("https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU")
                              .password("password")
                              .roles("USER");
          }
      }

下面展示一個更高階的示例,使用attribute exchange

      @Configuration
      @EnableWebSecurity
      public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .openidLogin()
                      .loginPage("/login")
                      .permitAll()
                      .authenticationUserDetailsService(new AutoProvisioningUserDetailsService())
                          .attributeExchange("https://www.google.com/.")
                              .attribute("email")
                                  .type("http://axschema.org/contact/email")
                                  .required(true)
                                  .and()
                              .attribute("firstname")
                                  .type("http://axschema.org/namePerson/first")
                                  .required(true)
                                  .and()
                              .attribute("lastname")
                                  .type("http://axschema.org/namePerson/last")
                                  .required(true)
                                  .and()
                              .and()
                          .attributeExchange(".yahoo.com.")
                              .attribute("email")
                                  .type("http://schema.openid.net/contact/email")
                                  .required(true)
                                  .and()
                              .attribute("fullname")
                                  .type("http://axschema.org/namePerson")
                                  .required(true)
                                  .and()
                              .and()
                          .attributeExchange(".myopenid.com.")
                              .attribute("email")
                                  .type("http://schema.openid.net/contact/email")
                                  .required(true)
                                  .and()
                              .attribute("fullname")
                                  .type("http://schema.openid.net/namePerson")
                                  .required(true);
          }
      }
     
      public class AutoProvisioningUserDetailsService implements
              AuthenticationUserDetailsService&lt;OpenIDAuthenticationToken&gt; {
          public UserDetails loadUserDetails(OpenIDAuthenticationToken token) throws UsernameNotFoundException {
              return new User(token.getName(), "NOTUSED", AuthorityUtils.createAuthorityList("ROLE_USER"));
          }
      }

增加響應安全報文頭

預設情況下當使用WebSecuirtyConfigAdapter的預設建構函式時啟用。

僅觸發Headers()方法而不觸發其它方法或者接受WebSecurityConfigureerAdater預設的,等同於:

      @Configuration
      @EnableWebSecurity
       public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .headers()
                      .contentTypeOptions();
                      .xssProtection()
                      .cacheControl()
                      .httpStrictTransportSecurity()
                      .frameOptions()
                      .and()
                  ...;
          }
      }

取消安全報文頭,如下:

      @Configuration
      @EnableWebSecurity
      public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .headers().disable()
                  ...;
          }
      }

使用部分安全報文頭

觸發headers()方法的返回結果,例如,只使用HeaderConfigurer的cacheControll()方法和HeadersConfigurer的frameOptions()方法.

      @Configuration
      @EnableWebSecurity
      public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .headers()
                      .cacheControl()
                      .frameOptions()
                      .and()
                  ...;
          }
      }

配置session管理

下面的配置展示了只允許認證使用者在同一時間只有一個例項是如何配置的。若一個使用者使用使用者名稱為"user"認證並且沒有退出,同一個名為“user”的試圖再次認證時,第一個使用者的session將會強制銷燬,並設定到"/login?expired"的url。

            @Configuration
      @EnableWebSecurity
      public class SessionManagementSecurityConfig extends
              WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .anyRequest().hasRole("USER")
                      .and()
                 .formLogin()
                      .permitAll()
                      .and()
                 .sessionManagement()
                      .maximumSessions(1)
                      .expiredUrl("/login?expired");
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth.
                  inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

當使用SessionManagementConfigurer的maximumSessio(int)時不用忘記為應用配置HttpSessionEventPublisher,這樣能保證過期的session能夠被清除。

在web.xml中可以這樣配置:

      <listener>
           <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>;
      </listener>

配置PortMapper

允許配置一個從HttpSecurity的getSharedObject(Class)方法中獲取的PortMapper。當http請求跳轉到https或者https請求跳轉到http請求時(例如我們和requiresChanenl一起使用時),別的提供的SecurityConfigurer物件使用P誒賬戶的PortMapper作為預設的PortMapper。預設情況下,spring security使用PortMapperImpl來對映http埠8080到https埠8443,並且將http埠的80對映到https的埠443.

配置示例如下,下面的配置將確保在spring security中的http請求埠9090跳轉到https埠9443 並且將http埠80跳轉到https443埠。

      @Configuration
      @EnableWebSecurity
      public class PortMapperSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin()
                      .permitAll()
                      .and()
                      // Example portMapper() configuration
                      .portMapper()
                          .http(9090).mapsTo(9443)
                          .http(80).mapsTo(443);
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth
                  .inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

配置基於容器的預認證

在這個場景中,servlet容器管理認證。

配置示例:

下面的配置使用HttpServletRequest中的principal,若使用者的角色是“ROLE_USER”或者"ROLE_ADMIN",將會返回Authentication結果。

    @Configuration
      @EnableWebSecurity
      public class JeeSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  // Example jee() configuration
                  .jee()
                      .mappableRoles("ROLE_USER", "ROLE_ADMIN");
          }
      }

開發者希望使用基於容器預認證時,需要在web.xml中配置安全限制。例如:

 <login-config>
          <auth-method>FORM</auth-method>
          <form-login-config>
              <form-login-page>/login</form-login-page>
              <form-error-page>/login?error</form-error-page>
          </form-login-config>
      </login-config>
     
      <security-role>
          <role-name>ROLE_USER</role-name>
      </security-role>
      <security-constraint>
          <web-resource-collection>
          <web-resource-name>Public</web-resource-name>
              <description>Matches unconstrained pages</description>
              <url-pattern>/login</url-pattern>
              <url-pattern>/logout</url-pattern>
              <url-pattern>/resources/</url-pattern>
          </web-resource-collection>
      </security-constraint>
      <security-constraint>
          <web-resource-collection>
              <web-resource-name>Secured Areas</web-resource-name>
              <url-pattern>/</url-pattern>
          </web-resource-collection>
          <auth-constraint>
              <role-name>ROLE_USER</role-name>
          </auth-constraint>
      </security-constraint>

配置基於X509的預認證

配置示例,下面的配置試圖從X509證書中提取使用者名稱,注意,為完成這個工作,客戶端請求證書需要配置到servlet容器中。

      @Configuration
      @EnableWebSecurity
      public class X509SecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  // Example x509() configuration
                  .x509();
          }
      }

配置Remember-me服務

配置示例,下面的配置展示瞭如何允許基於token的remember-me的認證。若http引數中包含一個名為“remember-me”的引數,不管session是否過期,使用者記錄將會被記儲存下來。

 @Configuration
      @EnableWebSecurity
      public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin()
                      .permitAll()
                      .and()
                   // Example Remember Me Configuration
                  .rememberMe();
          }
      }

限制HttpServletRequest的請求訪問

配置示例,最基本的示例是配置所有的url訪問都需要角色"ROLE_USER".下面的配置要求每一個url的訪問都需要認證,並且授權訪問許可權給使用者"admin"和"user".

             @Configuration
      @EnableWebSecurity
      public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER")
                             .and()
                        .withUser("adminr")
                             .password("password")
                             .roles("ADMIN","USER");
          }
      }

同樣,也可以配置多個url。下面的配置要求以/admin/開始的url訪問許可權為“admin”使用者。

 @Configuration
      @EnableWebSecurity
      public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/admin/**").hasRole("ADMIN")
                      .antMatchers("/**").hasRole("USER")
                      .and()
                  .formLogin();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER")
                             .and()
                        .withUser("adminr")
                             .password("password")
                             .roles("ADMIN","USER");
          }
      }

注意:匹配起效是按照順序來的。因此如果下面的配置是無效的,因為滿足第一個規則後將不會檢查第二條規則:

      http
          .authorizeRequests()
              .antMatchers("/**").hasRole("USER")
              .antMatchers("/admin/**").hasRole("ADMIN")

增加CSRF支援

預設情況下,當使用WebSecurityConfigurerAdapter時的預設構造方法時CSRF是啟用的。你可以使用如下方法關閉它:

      @Configuration
      @EnableWebSecurity
      public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .csrf().disable()
                  ...;
          }
      }

增加logout支援

預設支援,當使用WebSecurityConfigurerAdapter時Logout是支援的。當使用者發出“/logout”請求時,系統將會銷燬session並且清空配置的rememberMe()認證,然後清除SecurityContextHolder,最後跳向logout成功頁面或者登陸頁面。

 @Configuration
      @EnableWebSecurity
      public class LogoutSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin()
                      .and()
                  // sample logout customization
                  .logout()
                      .logout()
                         .deleteCookies("remove")
                         .invalidateHttpSession(false)
                         .logoutUrl("/custom-logout")
                         .logoutSuccessUrl("/logout-success");
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
      }

匿名使用者控制

使用WebSecurityConfigurerAdapter時自動繫結。預設情況下,匿名使用者有一個AnonymousAuthenticationToken標示,包含角色"ROLE_ANONYMOUS"。

下面的配置展示瞭如何指定匿名使用者應該包含"ROLE_ANON".

             @Configuration
      @EnableWebSecurity
      public class AnononymousSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin()
                      .and()
                  // sample anonymous customization
                  .anonymous()
                      .authorities("ROLE_ANON");
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
      }

基於表單的認證

若FormLoginConfigurer的loginpage(String)沒有指定,將會產生一個預設的login頁面。

示例配置:

 @Configuration
      @EnableWebSecurity
      public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER")
                      .and()
                  .formLogin();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
      }

下面的示例展示了自定義的表單認證:

 @Configuration
      @EnableWebSecurity
      public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/").hasRole("USER")
                      .and()
                  .formLogin()
                         .usernameParameter("j_username") // default is username
                         .passwordParameter("j_password") // default is password
                         .loginPage("/authentication/login") // default is /login with an HTTP get
                         .failureUrl("/authentication/login?failed") // default is /login?error
                         .loginProcessingUrl("/authentication/login/process"); // default is /login with an HTTP post
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
      }

配置安全通道

為使配置生效,需至少配置一個通道的對映。

配置示例:

下面例子展示瞭如何將每個請求都使用https通道。

 @Configuration
      @EnableWebSecurity
      public class ChannelSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER")
                      .and()
                  .formLogin()
                      .and()
                  .channelSecurity()
                      .anyRequest().requiresSecure();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                   .inMemoryAuthentication()
                        .withUser("user")
                             .password("password")
                             .roles("USER");
          }
      }

配置http 基本認證

配置示例:

 @Configuration
      @EnableWebSecurity
      public class HttpBasicSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER").and()
                      .httpBasic();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                  .inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

配置要觸發的HttpRequest

重寫RequestMatcher方法、antMatcher()z、regexMatcher()等。

配置示例

下面的配置使HttpSecurity接收以"/api/","/oauth/"開頭請求。

 @Configuration
      @EnableWebSecurity
      public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .requestMatchers()
                      .antMatchers("/api/**","/oauth/**")
                      .and()
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER").and()
                      .httpBasic();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                  .inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

下面的配置和上面的相同:

 @Configuration
      @EnableWebSecurity
      public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .requestMatchers()
                      .antMatchers("/api/**")
                      .antMatchers("/oauth/**")
                      .and()
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER").and()
                      .httpBasic();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                  .inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

同樣也可以這樣使用:

@Configuration
      @EnableWebSecurity
      public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter {
     
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .requestMatchers()
                      .antMatchers("/api/**")
                      .and()
                  .requestMatchers()
                      .antMatchers("/oauth/**")
                      .and()
                  .authorizeRequests()
                      .antMatchers("/**").hasRole("USER").and()
                      .httpBasic();
          }
     
          @Override
          protected void configure(AuthenticationManagerBuilder auth)
                  throws Exception {
              auth
                  .inMemoryAuthentication()
                      .withUser("user")
                          .password("password")
                          .roles("USER");
          }
      }

 

小結:

   本文是從httpSecurity程式碼中整理得來的,有助於對spring security的全面理解。

 

相關文章