Spring Security 配置類屬性詳解

在我們前面的文章Spring Security 初識(一)中,我們看到了一個最簡單的
Spring Security 配置,會要求所有的請求都要經過認證.但是,這並不是我們想要的,我們通常想自定義應用的安全性.因爲有些路徑我們想要誰都可以訪問.

Spring Security對此的實現也很簡單.關鍵在於重載 WebSecurityConfigurerAdapter 的 configure() 方法.

我們使用最簡單的基於內訓的用戶存儲來演示Spring Security 的請求攔截,首先 就是 SecurotyConfigure 的實現.如下:

/**
 * @author itguang
 * @create 2017-12-28 9:19
 **/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //基於內存的用戶存儲
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("itguang").password("123456").roles("USER").and()
                .withUser("admin").password("123456").roles("ADMIN");
    }

    //請求攔截
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/shop/hello").authenticated()
                .antMatchers(HttpMethod.POST,"/shop/order").authenticated()
                .anyRequest().permitAll();
    }
}


先來 解釋一下 configure(HttpSecurity http) 方法,在解釋之前我們可以先看 WebSecurityConfigurerAdapter 裏面的默認實現:

/**
     * Override this method to configure the {@link HttpSecurity}. Typically subclasses
     * should not invoke this method by calling super as it may override their
     * configuration. The default configuration is:
     *
     * <pre>
     * http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
     * </pre>
     *
     * @param http the {@link HttpSecurity} to modify
     * @throws Exception if an error occurs
     */
    // @formatter:off
    protected void configure(HttpSecurity http) throws Exception {
        logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");

        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin().and()
            .httpBasic();
    }

默認的實現是什麼意思呢? 通過之前我們的測試和查看源碼,不難理解. HttpSecurity 實現了一個 HttpSecurityBuilder 接口,這是一個構造器接口.

因此可以使用構造器典型的鏈式調用風格.通過調用authorizeRequests()和 anyRequest().authenticated()就會要求所有進入應用的
HTTP請求都要進行認證。它也配置Spring Security支持基於表單的登錄以及HTTP Basic方式的認證。

接下來再看看我們的實現: 我們只是配置了 “/shop/hello” 和 “/shop/order” 這兩個路徑必須進過認證,並且 “/shop/order” 必須是 post 請求的方式.對於其他的請求,
我們都是 .anyRequest().permitAll() ;都放行.

具體的controller請查看源碼,文章最後會給出.

最後我們進行測試,會發現: 訪問 “/shop/hello” 和”/shop/order” 瀏覽器會返回給我們一個空白頁,如下圖:

這是因爲我們並沒有配置未授權時的登錄頁面.

antMatchers()方法中設定的路徑支持Ant風格的通配符。在這裏我們並沒有這樣使用,但是也可以使用通配符來指定路徑,如下所示:

.antMatchers("/shop/**").authenticated();

    我們也可以在一個對antMatchers()方法的調用中指定多個路徑:

    .antMatchers("/shop/hello","/shop/order").authenticated();

      antMatchers()方法所使用的路徑可能會包括Ant風格的通配符,而regexMatchers()方法則能夠接受正則表達式來定義請求路徑。
      例如,如下代碼片段所使用的正則表達式與“/spitters/**”(Ant風格)功能是相同的:

      .regexMatchers().authenticated();

        除了路徑選擇,我們還通過authenticated()和permitAll()來定義該如何保護路徑。authenticated()要求在執行該請求時,
        必須已經登錄了應用。如果用戶沒有認證的話,Spring Security的Filter將會捕獲該請求,並將用戶重定向到應用的登錄頁面。
        同時,permitAll()方法允許請求沒有任何的安全限制。

        除了authenticated()方法和permitAll()方法外,還有一些其他方法用來定義該如何保護請求.

        • access(String) 如果給定的SpEL表達式計算結果爲true,就允許訪問
        • anonymous() 允許匿名用戶訪問
        • authenticated() 允許認證的用戶進行訪問
        • denyAll() 無條件拒絕所有訪問
        • fullyAuthenticated() 如果用戶是完整認證的話(不是通過Remember-me功能認證的),就允許訪問
        • hasAuthority(String) 如果用戶具備給定權限的話就允許訪問
        • hasAnyAuthority(String…)如果用戶具備給定權限中的某一個的話,就允許訪問
        • hasRole(String) 如果用戶具備給定角色(用戶組)的話,就允許訪問/
        • hasAnyRole(String…) 如果用戶具有給定角色(用戶組)中的一個的話,允許訪問.
        • hasIpAddress(String 如果請求來自給定ip地址的話,就允許訪問.
        • not() 對其他訪問結果求反.
        • permitAll() 無條件允許訪問
        • rememberMe() 如果用戶是通過Remember-me功能認證的,就允許訪問

        通過上面的方法,我們可以修改 configure 方法,要求用戶不僅需要認證,還需要具備相應的權限

          /**
             * 請求攔截
             * @param http
             * @throws Exception
             */
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                        .antMatchers("/hello").hasAnyAuthority("ROLE_DELETE")
                        .antMatchers(HttpMethod.POST,"/order").hasAnyAuthority("ROLE_UPDATE")
                        .anyRequest().permitAll();
            }
        

        作爲代替方案,我們還可以使用 hasRole() ,它會自動使用 “ROLE_” 前綴.

          /**
             * 請求攔截
             * @param http
             * @throws Exception
             */
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                        .antMatchers("/hello").hasRole("DELETE")
                        .antMatchers(HttpMethod.POST,"/order").hasRole("UPDATE")
                        .anyRequest().permitAll();
            }
        

        注意:這些規則會按照給定的順序發揮作用。所以,很重要的一點就是將最爲具體的請求路徑放在前面,
        而最不具體的路徑(如anyRequest())放在最後面。如果不這樣做的話,那不具體的路徑配置將會覆蓋掉更爲具體的路徑配置。

        使用Spring表達式進行安全保護

        上面的方法中,我們看到一個 access() 方法,此方法可以接收一個Spel表達式讓我們對請求進行攔截.

        如下就是使用SpEL表達式來聲明具有“HELLO”角色才能訪問“/shop/hello”URL:

        .antMatchers("/shop/hello").access("hasRole('HELLO')");

          這個對“/shop/hello”的安全限制與開始時的效果是等價的,只不過這裏使用了SpEL來描述安全規則。
          如果當前用戶被授予了給定角色的話,那hasRole()表達式的計算結果就爲true。

          下面列出了Spring Security 支持的所有SPEL表達式:

          • authentication 用戶的認證對象
          • denyAll 結果始終爲false
          • hasAnyRole(list of roles) 如果用戶被授予了列表中任意的指定角色,結果爲true
          • hasRole(role) 如果用戶被授予了指定的角色,結果爲true
          • hasIpAddress(IPAddress) 如果請求來自指定IP的話,結果爲true
          • isAnonymous() 如果當前用戶爲匿名用戶,結果爲true
          • isAuthenticated() 如果當前用戶進行了認證的話,結果爲true
          • isFullyAuthenticated() 如果當前用戶進行了完整認證的話(不是通過Remember-me功能進行的認證),結果爲true
          • isRememberMe() 如果當前用戶是通過Remember-me自動認證的,結果爲true
          • permitAll() 結果始終爲true
          • principal() 用戶的principal對象

          小結

          這節我們講了如何使用 HttpSecurity 進行細緻的請求攔截,
          此外,Spring Security 還支持防止跨站請求僞造(cross-site request forgery,CSRF,
          和視圖保護的功能,
          這裏就不再細講,感興趣的可以參考: spring in action 一書的 9.3.3 和 9.5 節.

          源碼地址:https://github.com/itguang/security/blob/master/spring-security-demo4/README.md

          發表評論
          所有評論
          還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
          相關文章