讀古今文學網 > Spring Boot實戰 > 7.5 保護Actuator端點 >

7.5 保護Actuator端點

很多Actuator端點發佈的信息都可能涉及敏感數據,還有一些端點,(比如/shutdown)非常危險,可以用來關閉應用程序。因此,保護這些端點尤為重要,能訪問它們的只能是那些經過授權的客戶端。

實際上,Actuator的端點保護可以用和其他URL路徑一樣的方式——使用Spring Security。在Spring Boot應用程序中,這意味著將Security起步依賴作為構建依賴加入,然後讓安全相關的自動配置來保護應用程序,其中當然也包括了Actuator端點。

在第3章,我們看到了默認安全自動配置如何把所有URL路徑保護起來,要求HTTP基本身份驗證,用戶名是user,密碼在啟動時隨機生成並寫到日誌文件裡去。這不是我們所希望的Actuator保護方式。

我們已經添加了一些自定義安全配置,僅限帶有READER權限的授權用訪問根URL路徑(/)。要保護Actuator的端點,我們需要對SecurityConfig.javaconfigure方法做些修改。

舉例來說,你想要保護/shutdown端點,僅允許擁有ADMIN權限的用戶訪問,代碼清單7-13就是新的configure方法。

代碼清單7-13 保護/shutdown端點

@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .authorizeRequests
      .antMatchers(\"/\").access(\"hasRole(\'READER\')\")
      .antMatchers(\"/shutdown\").access(\"hasRole(\'ADMIN\')\")    ←---要求有ADMIN權限
      .antMatchers(\"/**\").permitAll
    .and
    .formLogin
      .loginPage(\"/login\")
      .failureUrl(\"/login?error=true\");
}

  

現在要訪問/shutdown端點,必須用一個帶ADMIN權限的用戶來做身份驗證。

然而,第3章裡的自定義UserDetailsService只對通過ReaderRepository加載的用戶賦予READER權限。因此,你需要創建一個更聰明的UserDetailsService實現,對某些用戶賦予ADMIN權限。你可以配置一個額外的身份驗證實現,比如代碼清單7-14里的內存實現。

代碼清單7-14 添加一個內存裡的admin用戶

@Override
protected void configure(
            AuthenticationManagerBuilder auth) throws Exception {
  auth
    .userDetailsService(new UserDetailsService {    ←---Reader身份驗證
      @Override
      public UserDetails loadUserByUsername(String username)
          throws UsernameNotFoundException {
        UserDetails user = readerRepository.findOne(username);
        if (user != null) {
          return user;
        }
        throw new UsernameNotFoundException(
                      \"User \'\" + username + \"\' not found.\");
      }
    })
    .and
    .inMemoryAuthentication
      .withUser(\"admin\").password(\"s3cr3t\")
                        .roles(\"ADMIN\", \"READER\");    ←---Admin身份驗證
}

  

新加的內存身份驗證中,用戶名定義為admin,密碼為s3cr3t,同時被授予ADMIN和READER權限。

現在,除了那些擁有ADMIN權限的用戶,誰都無法訪問/shutdown端點。但Actuator的其他端點呢?假設你只想讓ADMIN的用戶訪問它們(像/shutdown一樣),可以在調用antMatchers時列出這些URL。例如,要保護/metrics、/confiprops和/shutdown,可以像這樣調用antMatchers

.antMatchers(\"/shutdown\", \"/metrics\", \"/configprops\")
                          .access(\"hasRole(\'ADMIN\')\")

  

雖然這麼做能奏效,但也只適用於少數Actuator端點的保護。如果要保護全部Actuator端點,這種做法就不太方便了。

比起在調用antMatchers方法時顯式地列出所有的Actuator端點,用通配符在一個簡單的Ant風格表達式裡匹配全部的Actuator端點更容易。但是,這麼做也小有點挑戰,因為不同的端點路徑之間沒有什麼共同點,我們也不能在/**上運用ADMIN權限。這樣一來,除了根路徑(/)之外,什麼要有ADMIN權限。

為此,可以通過management.context-path屬性設置端點的上下文路徑。默認情況下,這個屬性是空的,所以Actuator的端點路徑都是相對於根路徑的。在application.yaml裡增加如下內容,可以讓這些端點都帶上/mgmt前綴。

management:
  context-path: /mgmt

  

你也可以在application.properties裡做類似的事情:

management.context-path=/mgmt

  

management.context-path設置為/mgmt後,所有的Actuator端點都會與/mgmt路徑相關。例如,/metrics端點的URL會變為/mgmt/metrics。

有了這個新的路徑,我們就有了公共的前綴,在為Actuator端點賦予ADMIN權限限制時就能借助這個公共前綴:

.antMatchers(\"/mgmt/**\").access(\"hasRole(\'ADMIN\')\")

  

現在所有以/mgmt開頭的請求(包含了所有的Actuator端點),都只讓授予了ADMIN權限的認證用戶訪問。