很多Actuator端點發佈的信息都可能涉及敏感數據,還有一些端點,(比如/shutdown)非常危險,可以用來關閉應用程序。因此,保護這些端點尤為重要,能訪問它們的只能是那些經過授權的客戶端。
實際上,Actuator的端點保護可以用和其他URL路徑一樣的方式——使用Spring Security。在Spring Boot應用程序中,這意味著將Security起步依賴作為構建依賴加入,然後讓安全相關的自動配置來保護應用程序,其中當然也包括了Actuator端點。
在第3章,我們看到了默認安全自動配置如何把所有URL路徑保護起來,要求HTTP基本身份驗證,用戶名是user,密碼在啟動時隨機生成並寫到日誌文件裡去。這不是我們所希望的Actuator保護方式。
我們已經添加了一些自定義安全配置,僅限帶有READER權限的授權用訪問根URL路徑(/)。要保護Actuator的端點,我們需要對SecurityConfig.java
的configure
方法做些修改。
舉例來說,你想要保護/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權限的認證用戶訪問。