65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 .NET 属性的 Web 应用程序授权安全模型

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (5投票s)

2008年7月26日

CPOL

5分钟阅读

viewsIcon

33245

downloadIcon

257

本文将讨论使用 .NET 属性的 Web 应用程序中的授权安全模型。

引言

如今,Web 应用程序的安全性至关重要;尤其是考虑到日常攻击日益增多。但在本文中,我们不讨论 Web 应用程序的身份验证,而是讨论一种简单而强大的授权方法。

背景

在 Web 应用程序安全模型中,有两个基本术语:身份验证 (Authentication) 和授权 (Authorization);区分两者非常重要。

授权是系统安全地识别用户,了解用户是谁以及用户是否是其声称的那种人的机制。

身份验证是系统确定已通过身份验证的用户对系统中的安全资源应具有的访问级别的机制。这包括:访问资源和执行操作。

本文重点关注授权。由于存在多种授权方式(本文不一一讨论),我们将重点讨论其中一种:使用 .NET 属性。

使用代码

.NET 属性是一个可以应用于其他类、方法、委托、属性等的标头中的类,并且它应该继承自 System.Attribute 类。我们将创建自己的属性,如下所示:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary />
/// Summary description for PrivilegedObjectAttribute
/// </summary />
[AttributeUsage(AttributeTargets.Class | 
         AttributeTargets.Method, AllowMultiple = false)]
public class PrivilegedObjectAttribute : System.Attribute
{
    private string m_PrivilegeCode;

    public string PrivilegeCode
    {
        get { return m_PrivilegeCode; }
        set { m_PrivilegeCode = value; }
    }

    public PrivilegedObjectAttribute(string privilegeCode)
    {
        m_PrivilegeCode = privilegeCode;
    }
}

此属性类将用于类和方法。当然,如果您愿意,可以识别更多这类用途,但为了演示的目的,我们只使用这两种。

AllowMultiple 属性指示是否可以在每个类或方法上使用多个属性,我们将为每个类或方法仅使用一种权限。

请注意,我们有一个简单的权限对象,它只有一个作为字符串的权限代码属性,我们将使用它。

接下来,我们将使用 BasePage 类来处理页面,使用 BaseUserControl 来处理用户控件。 BasePage 继承自 System.Web.UI.Page 类,并且应用程序中我们想要应用权限的每个页面都应该继承自 BasePage 类。这是为了代码重用,并且相同的代码将处理所有页面的授权。

BasePage 中最重要的方法是 OnInit 方法;我们将重写此方法以包含我们的授权代码,BasePage 的外观将如下所示:

public class BasePage : Page
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        //Get User ID
        int userID = SecurityHelper.UserID;

        //Get Current Page Privilege
        string pagePrivilegeCode = SecurityHelper.GetPrivilegeCode(this);

        //If the page doesnt have a privilege code you can either make it 
        ///accessilbe by default (which we will use here) or not accessible
        if (!string.IsNullOrEmpty(pagePrivilegeCode))
        {

            //Does the Current User Has the privilege
            bool authorized = 
              SecurityHelper.UserHasThePrivilege(userID, pagePrivilegeCode);

            //Raise Authorization Decision
            SecurityHelper.RaiseAuthorizationDescision(this, authorized);
        }
    }
}

现在,当用户需要授权时,在请求应用程序中的页面时,他将首先进入该页面的基页,在那里他将被要求提供授权信息。这发生在页面的 OnInit 生命周期中。

现在,为了对特定页面应用权限,例如 HumanResources.aspx 页面,该页面的代码隐藏将如下所示:

[PrivilegedObject ("PRV_HUMANRESOURCES")]
public partial class HumanResources : BasePage
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}

注意 PrivilegedObject 属性的用法。它将一个字符串作为参数,该字符串将指示页面的权限。当然,您可以使用枚举而不是字符串,例如。请注意,每个页面都有自己的权限,并且只有一个权限。已通过身份验证的用户应将这些权限存储在数据库中,例如,因此在添加具有新权限的新页面时,您还必须将该权限添加到数据库中,以便管理员用户可以将该权限映射到普通用户。

总结一下,.NET 的授权机制如下所示:

  • 获取已通过身份验证的用户 ID(以便稍后获取他的权限)
  • 获取当前页面的权限
  • 返回一个值,指示当前用户是否具有该权限
  • 引发授权决策,该决策通过指定授权对象(页面)和授权结果(已授权或未授权)来做出

RaiseAuthorizationDecision 方法要么使当前页面可访问,要么不。如果用户未获得授权,则可以将用户重定向到 AccessDenied 页面。

public static void RaiseAuthorizationDescision(object authorizationObject, bool authorized)
{
    if (!authorized)//Not Authorized
    {
        if (authorizationObject is Page)
        {
            Page currentPage = authorizationObject as Page;

            //Do Something like redirect the user to the AccessDenied Page
            currentPage.Response.Redirect("AccessDenied.aspx?BackUrl=" + 
            currentPage.Server.UrlEncode(currentPage.Request.UrlReferrer.PathAndQuery));
        }
        else if (authorizationObject is UserControl)
        {
            UserControl currentControl = authorizationObject as UserControl;

            //Do Something like redirect the user to a security information 
            //page which will explain why he is not accessable

            //...
            //...
        }
    }
}

AccessDenied 页面中,会有一个链接将用户重定向回他被拒绝授权之前的页面。

public partial class AccessDenied : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void btnBackUrl_Click(object sender, EventArgs e)
    {
        string backUrl=this.Request.QueryString ["BackUrl"];
        this.Response.Redirect(backUrl);
    }
}

几乎相同的概念适用于用户控件。主要区别在于用户未获得授权时采取的操作。您可能希望使用户控件对用户在页面上不可见,或者执行适合您应用程序的任何其他操作。

关注点

在实现此授权模型时,有几点需要注意:

  • 无权限页面:如果您添加了一个继承自 BasePage 类的页面,但未为其应用 PrivilegedObject 属性,则有两个选择:要么默认使该页面可访问,要么默认使其不可访问。对我而言,我认为我会将其默认设置为可访问。
  • 静态页面和动态页面:在本例中,到目前为止我们讨论的是静态页面,或者是在其中页面仅执行特定操作、视图或其他内容的静态页面功能,而不是动态页面,在动态页面中,页面的内容将根据某种业务逻辑动态变化 - 在这种情况下,特权页面将控制页面中的所有操作,因此您必须找到一种根据页面中的业务逻辑来控制它的方法,或者使用用户控件来授予动态权限。

摘要

此授权模型只是存在或您可以想到的众多其他授权模型中的一种,但我认为使用此模型存在一定的简洁性和清晰性。当然,您可以添加和增强此模型以适应您的业务。我曾使用过此模型,并已为本文简化了它。

© . All rights reserved.