iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Software Development

全端工程師團隊的養成計畫系列 第 17

Day17 透過 Filter 控管 backend API 存取權限

  • 分享至 

  • xImage
  •  

前期的基礎建設完成後,可以開始廣邀開發成員投入開發。此時不論是前端功能或後端 API 的數量,都會快速成長。前端功能在初期就已經有對應 RBAC 的角色控管,用來限制登入者可使用的功能。但後端呢?後端的 API 如果也能做到權限管理呢?本篇將討論本專案如何管理後端 Backend API 的存取權限。

先說明本專案的前端功能與使用者帳號權限管理機制。原則上,各別功能(如圖17-1 功能A1~C3)都會先分類到固定的 Group,每個新功能開發時就會分配到某個功能群組。而前端功能則透過管理者自行建立群組(如圖17-1 User Group1~99),並指定可使用的功能與使用者帳號。藉由這兩層關聯,就能管控各帳號可存取的 Controller。
圖17-1
圖17-1:功能群組權限設計
圖17-2
圖17-2:個人帳號可使用的功能清單示意圖

實作步驟

1.後端 backendAPI 專案中,增加 enumHelper.cs

    public static class EnumHelper_enumGroupTypeCode
    {
        public const string AppGroupA= "AppGroupA";
        public const string AppGroupB= "AppGroupB";
        public const string AppGroupC= "AppGroupC";

        public static readonly Dictionary<enumGroupTypeCode, string> GroupTypeCodeDictionary = new Dictionary<enumGroupTypeCode, string>
        {
            { enumGroupTypeCode.AppGroupA, AppGroupA},
            { enumGroupTypeCode.AppGroupB, AppGroupB},
            { enumGroupTypeCode.AppGroupC, AppGroupC},
        };

    }

2.後端 backendAPI 專案中 prgram.cs 加入授權策略。

 builder.Services.AddAuthorization(options =>
   {
      // 根據 enumGroupTypeCode 的字典生成授權策略
      foreach (var groupTypeCode in EnumHelper_enumGroupTypeCode.GroupTypeCodeDictionary)
        {
           options.AddPolicy(groupTypeCode.Value, policy =>
            policy.RequireClaim("GroupTypeCode", groupTypeCode.Key.ToString()));

         }
    });
  1. Program.cs 中加入 UseAuthenticationUseAuthorization,讓每個 HTTP 請求在進入 Controller 前,根據設定的授權策略(如角色、權限、Claims)進行檢查。如果沒有權限,則會回傳 403 Forbidden
    app.UseAuthentication();//驗證身份
    app.UseAuthorization();//授權驗證(提醒:通常要放置於app.UseRouting(); 之後、app.MapControllers(); 之前。)
  1. 建立 Controller.cs,加入 Filter,並指定可存取的 Policy,例如在 Controller 或 Action 上使用 [Authorize(Policy = "YourPolicyName")] 來限制只有符合該 Policy 的使用者才能存取。
namespace  backendAPI.Controllers
{
    [Authorize(Policy = EnumHelper_enumGroupTypeCode.AppGroupC)]
    [ApiController]
    [Route("api/[controller]")]
    public class PermissionController : ControllerBase
    {
        private readonly UserInfoService _userInfoService;
        public PermissionController(UserInfoService userInfoService)
        {
            _userInfoService = userInfoService ?? throw new ArgumentNullException(nameof(userInfoService));
        }
        // GET: api/permission
        [HttpGet]
        [ProducesResponseType(typeof(UserAccessDto), 200)]
        public async Task<IActionResult> GetPermission()
        {
            var emailClaim = User.FindFirst(ClaimTypes.Upn)?.Value;
            try {
                UserAccessDto? userInfo = await _userInfoService.GetUserInfobyEmail(emailClaim); 
            }
            catch (Exception ex)
            {
                Log.Error("Error ex : " + ex.TargetSite);
            }
            return Ok(userInfo );
        }
    }
}


驗證成果

  • 啟動服務,發送 API 請求,確認可以收到 403 Forbidden 回應。
    圖17-3
    圖17-3:發送 API 請求後,Filter 權限政策生效。

  • 調整 Filter,移除 Policy 驗證,確認可以收到 200 OK 回應。

namespace  backendAPI.Controllers
{
    [Authorize] // 僅驗證身份
    [ApiController]
    [Route("api/[controller]")]
    public class PermissionController : ControllerBase
    {
        private readonly UserInfoService _userInfoService;
        public PermissionController(UserInfoService userInfoService)
        {
            _userInfoService = userInfoService ?? throw new ArgumentNullException(nameof(userInfoService));
        }
        // GET: api/permission
        [HttpGet]
        [ProducesResponseType(typeof(UserAccessDto), 200)]
        public async Task<IActionResult> GetPermission()
        {
            var emailClaim = User.FindFirst(ClaimTypes.Upn)?.Value;
            try {
                UserAccessDto? userInfo = await _userInfoService.GetUserInfobyEmail(emailClaim); 
            }
            catch (Exception ex)
            {
                Log.Error("Error ex : " + ex.TargetSite);
            }
            return Ok(userInfo );
        }
    }
}

圖17-4
圖17-4:沒有 Filter 管控,可順利存取 PermissionController 下的 API 服務。

不過這個機制仍有調整的空間。回顧剛剛設計的範例,Holiday 僅被授權功能 B1,但也因此可以存取所有 GroupB 的 API 服務。因此,在個別 API 服務中,仍需要增加額外的邏輯處理來管控,以提升安全性與嚴謹度。
圖17-5
圖17-5:授權單一功能,便可存取整個 Controller 的所有API,仍有調整改善之處。

Ending Remark

透過本篇的說明與實作,我們展示了如何在後端 Backend API 中建立完整的存取權限管理機制。從前端功能群組與使用者帳號的權限規劃,到後端透過 JWT、Policy 與 Filter 的授權控制,每個 HTTP 請求都能依據角色、權限或 Claim 進行驗證,確保功能僅授權使用者可存取。

實作與驗證結果顯示,啟用 Policy 後,未授權的請求會正確回傳 403 Forbidden,移除 Policy 後則可順利取得 200 OK,說明權限控管機制運作正常且可靈活調整。整體設計不僅提升系統安全性,也為團隊提供可擴展、可維護的權限管理架構,適用於多角色、多功能的企業級專案。


上一篇
Day16 Azure Pipeline 可以幫我們的事(二)
下一篇
Day18 Vue 共用元件:打造簡易與 Confirm 對話視窗
系列文
全端工程師團隊的養成計畫20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言