如何對資源(前端頁面+後端接口)進行權限控制
在微服務架構中,請求的攔截在gateway中完成,而權限的查詢是在uaa中完成,在gateway和uaa集成部署的情況下實現較爲簡單,如果兩者分離實現起來就會比較麻煩,一種方案是在gateway的資源filter中內部調用uaa的權限查詢模塊,該方案是可行的,但是存在兩個弊端:
- 響應延時:每個資源的請求都會附帶一次uaa內部調用,加重uaa服務的負擔並延長了響應時間。
- 過度依賴:gateway作爲api網關,過度依賴了api提供方(uaa)的內部方法,導致系統耦合度提升。
因此應尋找一種低響應延時、鬆散依賴的解決方案:“token擴展”。
"token擴展"的思路爲在token形成時追加用戶資源權限(ar)屬性,在資源的攔截中獲取ar並與當前請求的資源比對,相當於將用戶的資源權限緩存到了token中,uaa通過客戶端瀏覽器將權限信息傳遞至gateway,gateway直接解析request獲取AR,避免了內部調用導致的過度依賴問題和相應延時問題。此方案應注意在用戶登錄期間的AR變動需在下次登錄後方能生效!!!
具體步驟如下:
- uaa中擴展token屬性(具體步驟參考最後部分),如在token中擴展ar屬性,內部包含當前用戶有權限訪問的前端頁面列表
{...,"ar":["a.html","b.html"]}
- gateway中攔截鑑權
//解析ar
Cookie accessTokenCookie = OAuth2CookieHelper.getAccessTokenCookie(request);
Map<String, Object> additionalInformation = tokenStore.readAccessToken(accessTokenCookie.getValue())
.getAdditionalInformation();
List<String> ar = (List<String>) additionalInformation.get("ar");
//鑑權
for (String resourceUrl : ar) {
if (resourceUrl == null) {
continue;
}
if (resourceUrl.startsWith(requestUri)) {
return false;
}
}
token 屬性擴展
org.springframework.security.oauth2.provider.token.TokenEnhancer#enhance提供了擴展token屬性的可能性,以下demo在token中增加ar屬性,並使用@Component注入容器以生效。
@Component
public class ArTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
addClaims((DefaultOAuth2AccessToken) accessToken,authentication);
return accessToken;
}
private void addClaims(DefaultOAuth2AccessToken token, OAuth2Authentication authentication) {
Map<String, Object> additionalInformation = token.getAdditionalInformation();
additionalInformation.put("ar", "something you like");
token.setAdditionalInformation(additionalInformation);
}
}