首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 授權全攻略:從角色基礎到聲明基礎與 STS 整合

     編輯:關於.NET

授權在分散式系統的核心地位

服務導向架構中,每次服務呼叫都跨越安全邊界。WCF 提供兩大授權模型:角色基礎授權(簡單、成熟)與聲明基礎授權(強大、靈活、面向未來)。選擇取決於系統複雜度與擴展需求。

第一部分:角色基礎授權(RBAC)

核心抽象:IIdentity 與 IPrincipal

  • IIdentity:身分資訊(姓名、驗證方式、是否已驗證)
  • IPrincipal:角色資訊,核心方法 bool IsInRole(string role)
  • Thread.CurrentPrincipal:執行緒靜態儲存,服務作業透過此存取授權上下文

三種角色來源策略

策略適用場景配置關鍵
Windows 角色內網、AD 環境預設行為,WindowsPrincipal
ASP.NET 角色提供者自訂資料庫、表單驗證principalPermissionMode="UseAspNetRoles"
自訂 IPrincipal複雜業務邏輯、快取、多租戶principalPermissionMode="Custom" + 授權策略

自訂 Principal 實作範例

public class CustomPrincipal : IPrincipal
{
    private readonly IIdentity _identity;
    private string[] _roles;
    private readonly Cache _cache = HttpRuntime.Cache;

    public CustomPrincipal(IIdentity identity) => _identity = identity;

    public IIdentity Identity => _identity;

    public bool IsInRole(string role)
    {
        EnsureRoles();
        return _roles.Contains(role);
    }

    public string[] Roles
    {
        get { EnsureRoles(); return _roles; }
    }

    protected virtual void EnsureRoles()
    {
        if (_roles != null) return;
        // 從資料庫/快取載入角色邏輯
        _roles = _cache["Roles_" + _identity.Name] as string[] 
                 ?? LoadRolesFromDatabase(_identity.Name);
        _cache["Roles_" + _identity.Name] = _roles;
    }
}

// 授權策略注入 Principal
public class AuthorizationPolicy : IAuthorizationPolicy
{
    public bool Evaluate(EvaluationContext ctx, ref object state)
    {
        var clientId = GetClientIdentity(ctx);
        ctx.Properties["Principal"] = new CustomPrincipal(clientId);
        return true;
    }
    // ... Id, Issuer 實作
}

集中式授權:ServiceAuthorizationManager

繼承 ServiceAuthorizationManager 並覆寫 CheckAccessCore,在單一位置攔截所有請求:

public class AuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext ctx)
    {
        string action = ctx.IncomingMessageHeaders.Action;
        if (action.EndsWith("/GetRoles"))
        {
            // 解析訊息內容,檢查參數與身分
            var buffer = ctx.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
            var msg = buffer.CreateMessage();
            var nav = buffer.CreateNavigator();
            // XPath 提取參數...
            string username = nav.SelectSingleNode("//username", nsmgr).Value;
            
            return ctx.ServiceSecurityContext.PrimaryIdentity.Name == username 
                   || ctx.GetPrincipal().IsInRole("Administrators");
        }
        return true;
    }
}

第二部分:聲明基礎授權(Claims-Based)

為什麼需要 Claims?

  • 角色只是布林決策,無法攜帶豐富屬性(採購額度、部門、專案權限)
  • 跨信任域、多憑證類型(Windows、X.509、UserName、SAML Token)
  • 聯盟身分識別、單一登入(SSO)、微服務架構

核心型別體系

  • Claim:單一資訊單元(型別 URI、值 Resource、權利 Right)
  • ClaimSet:Claim 集合 + 發行者,FindClaims/ContainsClaim 查詢
  • AuthorizationContext:ClaimSet 容器,透過 ServiceSecurityContext.Current.AuthorizationContext 存取
  • IAuthorizationPolicy:聲明轉換引擎,Evaluate 方法中轉換技術性聲明為業務聲明

聲明轉換管線

public class CustomerAuthPolicy : IAuthorizationPolicy
{
    public bool Evaluate(EvaluationContext ctx, ref object state)
    {
        // 1. 取得技術性身分聲明
        Claim idClaim = ctx.ClaimSets.FindIdentityClaim();
        
        // 2. 映射為業務使用者 ID
        string userId = MapToUserId(idClaim);
        
        // 3. 查詢業務屬性並建構新 ClaimSet
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, userId, Rights.Identity),
            new Claim("https://myschema/purchaselimit", GetPurchaseLimit(userId), Rights.PossessProperty),
            new Claim(ClaimTypes.Email, GetEmail(userId), Rights.PossessProperty)
        };
        
        ctx.AddClaimSet(this, new DefaultClaimSet(ClaimSet.System, claims));
        return true;
    }
}

服務作業中使用聲明授權


public void PlaceOrder(Order order)
{
    int limit = GetPurchaseLimitFromClaims();
    if (order.Total > limit) throw new FaultException("超過採購額度");
}

private int GetPurchaseLimitFromClaims()
{
    var ctx = ServiceSecurityContext.Current.AuthorizationContext;
    foreach (var set in ctx.ClaimSets)
    {
        foreach (var claim in set.FindClaims("https://myschema/purchaselimit", Rights.PossessProperty))
        {
            return int.Parse(claim.Resource.ToString());
        }
    }
    throw new Exception("缺少採購額度聲明");
}

第三部分:安全權杖服務(STS)與聯盟身分

STS 架構角色

  1. 驗證用戶身分
  2. 簽發包含聲明的安全權杖(SAML Token)
  3. 客戶端攜帶 Token 呼叫應用服務
  4. 服務驗證 Token 簽名與信任鏈

優勢

  • 授權邏輯集中於 STS,服務端無需實作聲明轉換
  • 跨信任域:多個 STS 建立信任關係,實現跨組織 SSO
  • 技術中立:服務只處理標準 Token,不綁定特定驗證機制

實作建議

  • 生產環境建議使用商用 STS(如 IdentityServer、Azure AD、AD FS)
  • WCF 內建 SecurityTokenService 基類僅供教學/原型
  • Zermatt (Microsoft.IdentityModel) 簡化開發,但已併入 .NET 4.5+ 核心庫

選型決策指南

| 系統特徵 | 推薦模型 | |-----------|----------| | 內網、Windows 整合、簡單角色 | 角色基礎 (Windows/ASP.NET) | | 自訂資料庫、需快取、複雜邏輯 | 角色基礎 (自訂 Principal) | | 多憑證類型、豐富屬性、微服務 | 聲明基礎 | | 跨組織、聯盟身分、SSO | 聲明基礎 + STS |

總結

WCF 授權模型隨系統複雜度演進:角色基礎解決「是誰、能做什麼」,聲明基礎解決「攜帶什麼屬性、跨域怎麼信任」。掌握 IAuthorizationPolicy 聲明轉換管線與 ServiceAuthorizationManager 集中攔截,是構建企業級安全架構的關鍵。STS 將授權邏輯進一步外部化,為雲原生與零信任架構奠基。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved