閒談軟體設計:安全聲明

更新於 發佈於 閱讀時間約 7 分鐘

上一篇 閒談軟體設計:Web 框架的選擇提到,離開 Spring framework 後,需要有安全檢查與資料庫交易管理相關的配套,現在就來聊聊與安全檢查相關的議題,不過這次只聊怎麼「聲明」每個請求需要的安全性。

Spring Security 的寫法

Spring framework 裡的 Spring Security 提供非常彈性 (複雜) 的設計,包含身分驗證權限檢查,這邊就先不討論身分驗證,只看權限檢查,Spring Security 有非常多種設定的方法,簡單一點的像是直接針對路徑設定 (範例來自官網):

或是彈性一點,針對每個函式設定 (範例來自官網):

除了 Role-based,也可以用 ACL (範例來自官網):

Javalin 的寫法

Spring Security 可以說是相當彈性,那 Javalin 呢?在官網上可以看到,能對每個 endpoint 設定對應的角色,雖然沒有 Spring Security 來的多樣性,但很多情況下是相當夠用的。

到這邊為止,不管是用 .requestMatchers("/api/user/**").hasRole("USER") 或是 @PreAuthorize(hasRole("ADMIN")),還是 app.get("/private", ctx -> ctx.result("Hello private"), Role.LOGGED_IN);,都是在做一件事:「聲明」這些請求需要怎樣的安全性。至於,是否滿足這些聲明,通常是框架幫忙處理了,讓開發者只需要聲明即可。

角色設計

回到這次要開發的系統。首先,系統有 O、M 和 S 三個不同組織階層 (細節不方便透露太多),及三個後端 (backends for frontends),針對不同的服務提供不同的 API endpoints,三個服務的帳號是分開管理,因此,A 服務的登入資訊是無法呼叫 B 服務的 API。

三個服務都有不同的角色設計,其中最複雜的,是每個資源階層都可以有擁有者 (owner)、管理者 (manager)、一般職員(staff) 以及財務 (finance) 四種角色。職員和財務都是唯讀 (read-only) 的角色,差別是財務相關的資料只有財務 (以及擁有者和管理員) 看的到,擁有者比管理者多了角色管理的權限。最重要的是,上層角色的權限適用於下層的資源,也就是 M 的管理員,也是S 的管理員。

函式風格的聲明

針對這樣的資源階層和角色階層,要怎麼聲明,確實有點麻煩。雖然 Java 的 annotation 很適合用來宣告,但在 runtime 處理 annotation 老實說我覺得很麻煩,我比較喜歡用別人寫好的,自己寫這些處理就有點懶,而且也不太符合 Javalin 的風格。最後,我希望使用起來的感覺像這樣:

一開始的 post,指這個 endpoint 要用 HTTP POST,/resources/{sId},是該 endpoint 的路徑,最後是這個 endpoint 的 handler,被一個 secured 的函式包裝過,這函式的原型像是這樣:

第一個參數是實際的 handler,第二個參數是聲明 (JavalinSecurityClaim),secured 回傳一個 wrapper,該 wrapper 在呼叫實際的 handler 之前,先呼叫 claim.fulfill,如果不滿足聲明會拋出例外,忽略實際的 handler。

該如何提供聲明?上面的例子,anySResponsible() 意思是指該使用者能對 S 負責,具體來說必須是 S 的管理者或擁有者,或是 M 的管理者或擁有者,又或是 O 的管理者或擁有者,感覺很複雜?實際上它只有一行:

這邊是我個人偏好的命名,讓程式碼可以像一般的句子,這一行由三個函式組成,isanyResponsible 和 of。先看 anyResponsible,它用 any 函式 將 anyManager 和 anyOwner 包起來,any 是一個用來組合聲明的函式,只要組合的聲明哩,有任一個聲明滿足,就算是滿足,因此 anyResponsible 代表只要 anyManager 或 anyOwner 任一個滿足,就算是滿足。

JavalinSecurityClaim 和 SecurityClaim 之間不是繼承關係,SecurityClaim 用來描述與框架無關的資訊,JavalinSecurityClaim 則是與特定框架綁定,將 SecurityClaim 的資訊包裝成能在特定框架中執行的物件。

有了 any,很容易組出「必須是 S 的管理者或擁有者,或是 M 的管理者或擁有者,又或是 O 的管理者或擁有者」,anyManager 將 RoleScope 這個 enum 的值 (O、M 和 S) 拿出來,各別產生一個 ScopedRoleSecurityClaim 物件,然後再用 any 組合起來。ScopedRoleSecurityClaim 的責任很簡單,檢查該使用者有沒有對應階層的角色。anyOwner 也比照辦理。

除了 any,還有 all,必須是組合的聲明全部滿足才算滿足,但目前實際使用上,還沒有用到 all 的情境。

該有什麼角色已經確定了,但要怎麼知道從哪個階層的資源開始檢查?這就由 of 來處理,of 產生一個 PathResourceResolver 物件,這物件從請求的 context 中取得路徑上的變數,以 anySResponsible() 為例,它會試圖取得 /resources/{sId} 中 {sId} 的值,作為資源的 ID。最後 is 只是把角色 (anySResponsible()) 和資源 (of("s")) 封裝成 JavalinSecurityClaim 物件。

小節

這次選擇用函式來做聲明,搭配一些輔助函式,可以組合出不同的聲明,像是 anyMResponsible,就是單純的 is(anyResponsibile(), of("m")),重點是透過函式組合,能重複利用,減少重複的程式碼。到這邊,就完成了聲明的設計,但是怎麼檢查這些聲明是否滿足,則是另一個故事了。

留言
avatar-img
留言分享你的想法!
Spirit-avatar-img
發文者
2025/06/29
閒談軟體設計:身家調查提及了這篇文章,趕快過去看看吧!
avatar-img
Spirit的沙龍
55會員
107內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
Spirit的沙龍的其他內容
2025/06/15
從Spring Boot轉換到Javalin的過程與考量,以及如何保持核心業務邏輯與Web框架的距離以提升專案彈性。文中比較了Micronaut, Helidon和Javalin三個輕量級框架,並說明選擇Javalin的原因及優缺點。
Thumbnail
2025/06/15
從Spring Boot轉換到Javalin的過程與考量,以及如何保持核心業務邏輯與Web框架的距離以提升專案彈性。文中比較了Micronaut, Helidon和Javalin三個輕量級框架,並說明選擇Javalin的原因及優缺點。
Thumbnail
2025/06/08
日誌設計包含幾個重要考量因素,包括關聯式查詢、雲端生態支援、情境豐富性、結構化日誌以及與商業邏輯核心保持距離。利用 correlation ID、ThreadLocal 以及自定義抽象物件,實現了這些需求,並簡潔地說明在不同任務發動情況下 (API請求、定時執行、事件驅動) 的使用
Thumbnail
2025/06/08
日誌設計包含幾個重要考量因素,包括關聯式查詢、雲端生態支援、情境豐富性、結構化日誌以及與商業邏輯核心保持距離。利用 correlation ID、ThreadLocal 以及自定義抽象物件,實現了這些需求,並簡潔地說明在不同任務發動情況下 (API請求、定時執行、事件驅動) 的使用
Thumbnail
2024/03/23
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
2024/03/23
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
看更多
你可能也想看
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
自由接案好像很自由、容易,卻需要點方向的指引,希望這篇的分享能給予你一些幫助。
Thumbnail
自由接案好像很自由、容易,卻需要點方向的指引,希望這篇的分享能給予你一些幫助。
Thumbnail
隨著企業在數位轉型過程中,愈來愈依賴多雲端架構,對雲端安全性和合規性的需求變得前所未有的重要。 雲原生應用程式保護平台(CNAPP)提供了一套全面的解決方案,讓企業能夠有效地管理多雲端環境中的安全性和合規性。
Thumbnail
隨著企業在數位轉型過程中,愈來愈依賴多雲端架構,對雲端安全性和合規性的需求變得前所未有的重要。 雲原生應用程式保護平台(CNAPP)提供了一套全面的解決方案,讓企業能夠有效地管理多雲端環境中的安全性和合規性。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
Anytype主要分為四區塊:目錄欄(Widget組成)、主編輯畫面、導航選單、設定區。
Thumbnail
Anytype主要分為四區塊:目錄欄(Widget組成)、主編輯畫面、導航選單、設定區。
Thumbnail
代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
Thumbnail
代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
Thumbnail
權限管理=新增、修改、刪除+審核 通常,這種程式的設計會包含權限管理,其中包括現場修改、刪除等三大類功能。然而,根據經驗,我們還需要關注另一類功能,即審核權限。 審核不執行新增 審核權限通常不執行新增的動作,僅限於某些欄位的輸入。新增、修改、刪除這些操作基本上是容易理解的。也就是說,對於這個工
Thumbnail
權限管理=新增、修改、刪除+審核 通常,這種程式的設計會包含權限管理,其中包括現場修改、刪除等三大類功能。然而,根據經驗,我們還需要關注另一類功能,即審核權限。 審核不執行新增 審核權限通常不執行新增的動作,僅限於某些欄位的輸入。新增、修改、刪除這些操作基本上是容易理解的。也就是說,對於這個工
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News