File Access Agent
File Access Agent 是檔案存取代理服務,用來控管 bucket / file space 裡檔案的上傳、下載、metadata 讀取與刪除權限。
本專案已決定使用 C# / ASP.NET Core。目標與授權模型依 ../member_center 最新文件整理,後續實作會以此為準落地。
已確認決策
- 部署模型採 single-tenant instance:一個 File Access Agent instance 只服務一個 tenant。
tenant_id仍是 token 與授權邊界的一部分,但服務端會驗證其必須等於本 instance 的固定 tenant。- 服務預設為無 DB、stateless access gateway。
- 每個 request 只處理單檔(upload/download/metadata/delete),不提供結構化查詢。
- 版本管理由上游服務負責;不同版本在 bucket 中視為不同單檔(不同
object_key或等價識別)。 - Agent 可只以
object_key或file_id作為單檔識別,不保存完整 metadata。
專案目的
此服務位於業務服務與實際檔案儲存 bucket 之間,負責檔案存取的安全邊界。
核心目的:
- 驗證由 Member Center 簽發的 OAuth2/JWT access token。
- 依
scope、tenant_id、aud、檔案識別與 HTTP method 判斷是否允許存取。 - 讓後端服務可以用 S2S token 上傳檔案。
- 讓後端服務在完成自身商業規則檢查後,向 Member Center 取得可給 client 使用的短效下載授權。
- 避免把一般 S2S access token 直接暴露給 client。
- 將 bucket provider 的直接存取權限集中在此服務或其 storage adapter 內。
Agent 角色定義
File Access Agent 是 access permission gateway,不是檔案主資料服務。
負責:
- 驗證 token 與 request 邊界(
tenant_id、scope、aud、method、object_key/file_id) - 代理單檔 upload/download/metadata/delete
- 呼叫 Member Center delegated token validation endpoint
不負責:
- delegated token 簽發(由 Member Center 負責)
- 商業規則與版本管理(由上游服務負責)
- 結構化查詢、報表或資料分析
- metadata 主資料治理(預設不落地 DB)
與 Member Center 的關係
Member Center 是 OAuth2/OIDC issuer 與 JWKS 提供者。File Access Agent 不負責會員登入、OAuth client 管理或長效 access token 簽發。
../member_center 目前已規劃並落地下列 File Access 相關授權設定:
- audience / resource:
file_access_api - OAuth client usage:
file_api - scopes:
files:upload.writefiles:download.readfiles:download.delegatefiles:metadata.readfiles:delete
最新版 member_center 文件已明確把 File Access 納入同一套租戶授權模型:file_api client 必須綁定 tenant_id,upload token 與 delegated download token 也都必須帶 tenant_id。
File Access Agent 應驗證:
- upload 的 S2S JWT:透過 Member Center JWKS 驗
iss、aud=file_access_api、exp、scope、tenant_id - download 的 delegated token:以 Member Center validation endpoint 線上驗證
- token 中的
tenant_id是否符合實際 request - token 中的
object_key或file_id是否符合實際 request - token 中的
method是否符合實際 request
待確認的檔案邊界 claim:
user_id:delegated download token 目前由 Member Center 文件定義為必帶,用於對應業務服務已驗過的使用者身分。owner_id/subject/client_id:可用於紀錄或限定上傳者。bucket/namespace/object_prefix:若 storage 需要多 bucket 或 prefix 隔離,應優先明確化。file_id/object_key:下載 token 必須綁定其中一種檔案識別。
預期流程
Upload: service to File Access Agent
- 業務服務以
client_credentials向 Member Center 取得 access token。 - token 需包含
aud=file_access_api、tenant_id與files:upload.write。 - 業務服務帶 Bearer token 呼叫 File Access Agent 上傳檔案。
- File Access Agent 驗 token、
tenant_id與檔案邊界後,寫入 bucket / file space。
Download: service to client to File Access Agent
- client 向業務服務要求下載檔案。
- 業務服務自行驗證商業規則與檔案權限。
- 業務服務以
files:download.delegate呼叫 Member CenterPOST /file-access/download-tokens取得短效 download token。 - download token 至少綁定
tenant_id、user_id、object_key或file_id、method=GET、短效exp。 - client 帶短效 token 直接向 File Access Agent 下載檔案。
- File Access Agent 以
files:download.read呼叫 Member CenterPOST /file-access/download-tokens/validate,帶上 token 與實際 GET request 邊界,驗證通過後放行。
責任邊界已確認:
- Member Center:簽發 upload 用的 S2S JWT、簽發 delegated short-lived download token、提供 download token validation endpoint。
- File Access Agent:驗證 upload JWT、呼叫 validation endpoint 驗 delegated download token、控管實際 bucket / file space 的讀寫。
- 業務服務:先驗商業規則與使用者檔案權限,再向 Member Center 申請 delegated download token。
初步 API 邊界
實際路由可在實作時調整,但能力邊界應維持清楚:
PUT /files/{object_key}:上傳檔案,需files:upload.writeGET /files/{object_key}:下載檔案,需files:download.readHEAD /files/{object_key}或GET /files/metadata/{object_key}:讀 metadata,需files:metadata.readDELETE /files/{object_key}:刪除檔案,需files:delete
本服務不負責提供 POST /download-tokens。該責任已在 Member Center:
POST /file-access/download-tokensPOST /file-access/download-tokens/validate
非目標
- 不負責會員註冊、登入、OAuth consent 或 OAuth client 管理。
- 不取代 Member Center 的 token issuer 職責。
- 不把 bucket credentials 發給 client。
- 不由 File Access Agent 判斷完整商業規則;業務服務仍需先判斷使用者是否可存取指定檔案。
- 不在語言與 storage provider 尚未決定前鎖死特定 SDK 或框架。
上傳命名與重複策略
- Agent 不做複雜命名規則;
object_key由介接服務決定。 - 相同
object_key再次上傳時,Agent 視為覆蓋(overwrite),不自動版本化。 - 若要避免檔名重複,介接服務應自行把
timestamp/uuid/業務主鍵放入object_key。 - 若要版本管理,介接服務需為每個版本使用不同
object_key(例如v0001,v0002)。 - 詳細命名建議請見
docs/API.md的 Upload 區段。
待決策
- bucket / object storage provider,例如 S3、GCS、Cloudflare R2、MinIO 或本機檔案系統。
- 是否需要「可選」持久化:token
jti、審計紀錄或特殊索引(預設不啟用)。 - object key 命名規則與 bucket / namespace / prefix 隔離策略。
- 檔案大小限制、content-type allowlist、病毒掃描與保留期限。
- 是否支援 presigned URL,或所有流量都經由 access agent proxy。
Storage 設定
API 支援兩種 provider:
Storage:Provider=local:使用本機檔案系統(Instance:StorageRoot)Storage:Provider=minio:使用 MinIO(S3 compatible)
MinIO 設定(src/FileAccessAgent.Api/appsettings.json):
Minio:Endpoint:例如localhost:9000Minio:AccessKeyMinio:SecretKeyMinio:BucketNameMinio:UseSsl:true|falseMinio:Region:可空
Docker
API Dockerfile 位於 src/FileAccessAgent.Api/Dockerfile,建置時請使用 repo root 作為 build context,讓 Docker 可以存取 Api、Application、Domain、Infrastructure project references。
建置 image:
docker build -f src/FileAccessAgent.Api/Dockerfile -t file-access-agent-api .
啟動 API(container 內 listen 8080):
docker run --rm -p 8080:8080 \
-e Instance__TenantId=d8107508-e6b9-4630-b982-c7bbb0cb228f \
-e Auth__Issuer=http://host.docker.internal:7850/ \
-e Auth__Audience=file_access_api \
-e Auth__RequireHttpsMetadata=false \
-e MemberCenter__BaseUrl=http://host.docker.internal:7850/ \
file-access-agent-api
若使用 local storage,建議掛載 volume,避免 container 移除後檔案遺失:
docker run --rm -p 8080:8080 \
-e Storage__Provider=local \
-e Instance__StorageRoot=/app/data/storage \
-v "$(pwd)/data/storage:/app/data/storage" \
file-access-agent-api
若使用 MinIO 且 MinIO 也在 Docker network 中,Minio__Endpoint 應使用 service/container DNS 名稱,例如 minio:9000;不要使用 container 內的 localhost:9000。
實作語言
本專案已決定使用 C# / ASP.NET Core。
C# / ASP.NET Core
- 與
member_center同語言,跨專案概念與維運一致。 - ASP.NET Core 對大檔串流、middleware、auth policy、DI、設定管理很成熟。
- 編譯期檢查較強,適合安全邊界服務。
- 可直接沿用
member_center的設定、OpenAPI、JWT / OAuth 與部署習慣。
目前實作方向會以 ASP.NET Core Web API 為主,並保留 storage adapter 抽象,避免過早綁死特定 bucket provider。
文件維護規則
每次改動功能、流程、API、scope、設定或部署方式時,都要同步更新文件。
優先更新順序:
README.md:專案目的、目前決策、執行方式與重要限制。docs/:若後續建立更細文件,放設計、API、流程、部署、決策紀錄。- API 規格:一旦路由與 payload 穩定,補 OpenAPI 或等價規格。
如果程式碼與文件不一致,應先修正 README 或在 README 標示尚未決定,避免讓文件變成過期假設。
目前文件:
docs/API.md:File Access Agent API 規格與 Member Center 整合契約docs/openapi.yaml:本專案 OpenAPI 草案docs/DATA_MODEL.md:可選持久化擴充(非預設)
測試專案
src/FileAccessAgent.TestSite:Redirect login 測試站(OIDC Authorization Code + PKCE)- 目的:透過 Member Center
web_loginclient 登入,取得並顯示 token/claims,並直接測試 Agent API(upload / download / head / metadata / delete / health) - 測試站採雙 token 模式:
web_logintoken:只用於身份展示(claims / user context)file_apiservice token(client credentials):用於呼叫 Agent 與 Member Center delegated token API
最小設定(src/FileAccessAgent.TestSite/appsettings.json):
MemberCenter:AuthorityMemberCenter:WebBaseUrl(Member Center Web,預設http://localhost:5080,供 redirect logout 使用)MemberCenter:ClientId(web_login)MemberCenter:ClientSecret(web_login public client 可留空)MemberCenter:CallbackPath(需與 Member Center OAuth client redirect URI 一致)MemberCenter:SignedOutCallbackPath(OIDC middleware callback,建議保留預設/signout-callback-oidc,不要與 direct logout callback 共用)MemberCenter:Scopes(建議openid email profile)MemberCenter:ServiceClientId(file_api)MemberCenter:ServiceClientSecret(file_api)MemberCenter:ServiceScopes(至少files:upload.write files:metadata.read files:delete files:download.delegate)FileAccessAgent:BaseUrlFileAccessAgent:TenantId
啟動:
dotnet run --project src/FileAccessAgent.TestSite/FileAccessAgent.TestSite.csproj- 進入首頁後點
Login,會導到 Member Center,再 redirect 回測試站 Logout會走 Member Center WebGET /account/logout?returnUrl=...,再 callback 回 TestSite/auth/logout-callback- 若 logout 後未回到 TestSite,而停在 Member Center,需在 Member Center Web 設定:
Auth__AllowedLogoutReturnUrlPrefixes=http://localhost:5091/
- 登入後可在同一頁直接執行
Upload、Download、Head、Get Metadata、Delete、Health Upload改為檔案挑選上傳;Object Key可選填(留空會自動產生demo/uploads/<timestamp>-<filename>)- 上傳成功後會保留回傳的
object_key供後續Metadata/Head/Download/Delete直接測試 - 另提供
Download (Invalid Token)測試,故意帶錯 token 驗證 Agent 拒絕邏輯 Download會先呼叫 Member CenterPOST /file-access/download-tokens申請 delegated token,再帶 token 呼叫 Agent 下載Download File走 sample 的直連模式:TestSite 僅向 Member Center 取 delegated token,接著把 client 轉址到 Agent 下載 URL(含短效access_token),下載流量不經 TestSite
目前狀態
- 專案目標已依
../member_center文件整理。 - 已確認使用 C# / ASP.NET Core。
tenant_id與 delegated download token 分工已依最新版member_center文件校正。- API 已提供 Dockerfile,可用 .NET 8 多階段建置產生 container image。
- 目前目錄中的 .NET skeleton 可作為正式起點,但仍需依最新流程補上 Member Center validation 串接。