如何:使用 WIF 和 ACS 在声明感知 ASP.NET 应用程序中实现声明授权

更新时间:2015 年 6 月 19 日

适用于:Azure

应用于

  • Microsoft® Azure™ 访问控制服务 (ACS)

  • Windows® Identity Foundation (WIF)

  • ASP.NET

总结

本主题介绍如何使用 WIF 和 ACS 在声明感知 ASP.NET Web 应用程序中实现基于声明的访问控制 (CBAC) 授权。

目录

  • 目标

  • 概述

  • 步骤摘要

  • 步骤 1 - 实现声明授权库

  • 步骤 2 - 将 ASP.NET 应用程序配置为使用声明授权库

  • 步骤 3 - 配置授权策略

  • 相关项

目标

  • 从应用程序外部化授权逻辑。

  • 在角色以外实施授权检查,可实现对授权的更详细控制。

  • 提供策略驱动的声明性授权管理。

概述

声明授权基于令牌中携带的信息(即声明)的使用。 当仅基于角色不足以做出授权决策时,声明授权很有用。 例如,在财务应用程序中,根据账龄及其他属性转账时,可以为同一角色设置不同的限制。 此类属性可以声明的形式与角色一起传入,因此可以更精细地微调授权决策。

步骤摘要

  • 步骤 1 - 实现声明授权库

  • 步骤 2 - 将 ASP.NET 应用程序配置为使用声明授权库

  • 步骤 3 - 配置授权策略

步骤 1 - 实现声明授权库

此步骤显示如何创建一个外部类库,该类库将从配置文件中读取访问策略并强制执行访问权限检查。 下面的示例演示如何实现一个基于邮政编码声明进行授权决策的声明授权库。

实现声明授权库

  1. 确保你正在以管理员模式运行 Visual Studio®。

  2. 解决方案资源管理器中右键单击所需的解决方案,添加一个新的“类库”项目,然后为它起个名称,例如 MyClaimsAuthorizationManager。

  3. 删除默认类 Class1.cs

  4. 添加一个新类,并为它起个名称,例如 ZipClaimsAuthorizationManager。 这将实现基于邮政编码的授权。

  5. 添加对 Microsoft.IdentityModel 的引用以及对 System.Web 程序集的引用。

  6. 添加以下声明。

    using System.IO;
    using System.Xml; 
    using Microsoft.IdentityModel.Claims; 
    using Microsoft.IdentityModel.Configuration; 
    
  7. 扩展 ClaimsAuthorizationManager 类,重写其 AccessCheck 方法,然后实现 ZipClaimsAuthorizationManager 类的构造函数。 你的代码应类似于如下内容。

    namespace MyClaimsAuthorizationManager 
    { 
        class ZipClaimsAuthorizationManager : ClaimsAuthorizationManager 
        { 
            private static Dictionary<string, int> m_policies = new Dictionary<string, int>(); 
    
            public ZipClaimsAuthorizationManager(object config) 
            { 
                XmlNodeList nodes = config as XmlNodeList; 
                foreach (XmlNode node in nodes) 
                { 
                    { 
                        //FIND ZIP CLAIM IN THE POLICY IN WEB.CONFIG AND GET ITS VALUE 
                        //ADD THE VALUE TO MODULE SCOPE m_policies 
                        XmlTextReader reader = new XmlTextReader(new StringReader(node.OuterXml)); 
                        reader.MoveToContent(); 
                        string resource = reader.GetAttribute("resource"); 
                        reader.Read(); 
                        string claimType = reader.GetAttribute("claimType"); 
                        if (claimType.CompareTo(ClaimTypes.PostalCode) == 0) 
                        { 
                            throw new ArgumentNullException("Zip Authorization is not specified in policy in web.config"); 
                        } 
                        int zip = -1; 
                        bool success = int.TryParse(reader.GetAttribute("Zip"),out zip); 
                        if (!success) 
                        { 
                            throw new ArgumentException("Specified Zip code is invalid - check your web.config"); 
                        } 
                        m_policies[resource] = zip; 
                    } 
                } 
            } 
            public override bool CheckAccess(AuthorizationContext context) 
            { 
                //GET THE IDENTITY 
                //FIND THE POSTALCODE CLAIM'S VALUE IN IT 
                //COMPARE WITH THE POLICY 
                int allowedZip = -1; 
                int requestedZip = -1; 
                Uri webPage = new Uri(context.Resource.First().Value); 
                IClaimsPrincipal principal = (IClaimsPrincipal)HttpContext.Current.User; 
                if (principal == null) 
                { 
                    throw new InvalidOperationException("Principal is not populate in the context - check configuration"); 
                } 
                IClaimsIdentity identity = (IClaimsIdentity)principal.Identity; 
                if (m_policies.ContainsKey(webPage.PathAndQuery)) 
                { 
                    allowedZip = m_policies[webPage.PathAndQuery]; 
                    requestedZip = -1; 
                    int.TryParse((from c in identity.Claims 
                                            where c.ClaimType == ClaimTypes.PostalCode 
                                            select c.Value).FirstOrDefault(), out requestedZip); 
                } 
                if (requestedZip!=allowedZip) 
                { 
                    return false; 
                } 
                return true; 
            } 
        } 
    }
    
  8. 编译解决方案以确保没有编译错误。

  9. 找到已编译的库,在本示例中为 MyClaimsAuthorizationManager.dll。 需要将该库放入 ASP.NET Web 应用程序的 bin 文件夹。

步骤 2 - 将 ASP.NET 应用程序配置为使用声明授权库

后续步骤将在 ASP.NET Web 应用程序中执行。 请不要添加对你在上一步中创建的声明授权管理器库的引用。 ASP.NET Web 应用程序应该“不知道”它,除非是在 web.config 中。

将 ASP.NET 应用程序配置为使用声明授权库

  1. 通过将以下条目添加到 web.config 中的 HttpModules 节(适用于随 Visual Studio 一起提供的开发 Web 服务器;对于 Internet Information Services (IIS) 版本 7,此配置应位于 system.webServer 节点下的 modules 节中),将 ASP.NET Web 应用程序配置为在其管道中包含 WIF ClaimsAuthorizationModule。

    <add name="ClaimsAuthorizationModule" 
         type="Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> 
    
  2. 通过将以下条目添加到 microsoft.identityModel.service 节点,将 ASP.NET Web 应用程序配置为使用你在上一步中实现的自定义授权库。

    <claimsAuthorizationManager type="MyClaimsAuthorizationManager.ZipClaimsAuthorizationManager, MyClaimsAuthorizationManager" >
    

步骤 3 - 配置授权策略

在本主题中,配置策略在 ASP.NET Web 应用程序的 web.config 文件中表示。 此策略带有的简单规则可将资源映射到声明类型及其值。 例如,可以通过在前面步骤中创建和配置的自定义授权库读取并强制实施以下策略。 将以下条目添加到上一步配置的 claimsAuthorizationManager 节点。

<policy resource="/default.aspx">
  <claim claimType=https://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode
  Zip="11111" />
</policy>

上面的策略要求传入令牌必须具有值为 11111 的邮政编码声明才能访问 default.aspx 页。