创建具有自定义权限的 DotNetNuke 模块
有关如何为模块设置添加自定义权限的教程。
引言
欢迎,热情的 DNN 模块开发者,来到这个演练。在这里,我将一步一步地介绍如何为 DNN 模块添加自定义权限。随着新信息的出现,本教程将来可能会发生变化;要了解最新动态,请订阅我的博客 RSS 订阅源。
首先,我们先来明确一下。以下是我在这个演练中所做的假设:
- 您了解基本的模块结构、DAL 和模块入门套件。
- 您正在使用已安装模块模板的 Visual Studio 或 Visual Studio Express。
- 您了解 C# 和 ASP.NET。
当然,这些都不是强制性的。不过,如果这些假设都适用,您的工作将会轻松得多。
您坐好了吗?那么,我们就开始吧……
步骤 1:创建一个虚拟模块
这是比较容易的部分。您应该以前做过,所以我将简要说明。在 Visual Web Developer 中转到您的 DNN 项目,右键单击顶层节点,然后选择“添加新项”。选择“DotNetNuke 动态模块”以及您选择的语言(本演练将使用 C#)。将模块名称输入为“PermissionTest”。按照说明重命名文件夹,不要忘记修改 web.config 文件,然后按 Ctrl-F5 启动您的 DNN 开发安装。转到 Host->Module Definitions,滚动到页面底部,单击“Import Module Definition”,选择您刚刚创建的模块的清单,然后单击“Import Manifest”。
您的模块应该会出现在已安装模块列表中,但有一个小错误需要处理。单击“PermissionTest”旁边的铅笔图标以显示模块属性页面。如果模块名称和文件夹名称文本框中有某种前缀(在我的例子中是 CreativeCats.PermissionTest),请删除该前缀,只留下“PermissionTest”。接下来,转到 Host->SQL,复制并粘贴在 DesktopModules/MODULENAME 文件夹中为您创建的“01.00.00.SqlDataProvider”文件的内容。确保选中“Run as Script”复选框,然后单击“Execute”。
如果我刚才的解释让您感到困惑,您可能需要回到Michael Washington 的教程系列,其中提供了有关如何创建简单模块的详细说明。
现在,转到您网站上的任何页面并安装该模块,以便了解到目前为止的代码是否正常。单击“Settings”以查看默认设置页面。您将看到所有模块通用的标准权限,“View Module”和“Edit Module”。这正是我们要更改的内容。
根据Vicenç Masanas 的博客文章,在模块安装期间没有自动创建自定义模块权限的方法,因此他建议使用 IUpgradeable
接口来实现此目的。是的,该博客是 2006 年的,但到目前为止,我还没有找到任何相反的信息,所以这是我使用的方法。(我看到有人建议在 page_load
事件期间创建权限,但我忍不住想知道这是否真的明智……不过,如果您知道我不知道的事情,请告诉我。)
纯粹出于开发目的,我们将通过在视图控件上放置一个按钮并将 button_click
事件处理程序连接起来添加权限来作弊。这只是为了给您一个机会在调试器中单步跟踪正在发生的事情,并允许在不持续卸载和重新安装模块的情况下进行测试。所以,在您的 ViewPermissionTest.ascx(或任何您命名的文件)底部添加一个按钮,双击它以在代码隐藏文件中添加事件处理程序,然后添加以下行:
PermissionTestController cntrl = new PermissionTestController();
cntrl.UpgradeModule("01.00.00");
步骤 2:实现 IUpgradeable 接口
首先,当然,我们需要将我们的控制器类声明为实现 IUpgradeable
接口。类声明应该看起来像这样:
public class PermissionTestController : ISearchable, IPortable, IUpgradeable
要实现 IUpgradeable
接口,我们需要在模块的控制器类中实现以下方法:
string UpgradeModule(string Version)
(控制器类已为您在 App_Code 目录中创建。我将我的模块命名为 PermissionTest,所以对我来说,控制器是“Visual Studio 2008\WebSites\DNN484\App_Code\PermissionTestController.cs”。)
执行此操作的标准方法是检查模块版本并调用您希望在升级期间发生的任何操作。在我们的例子中,通过私有方法 InitModulePermissions()
创建自定义权限。首先,您需要在控制器类中包含以下命名空间:
using DotNetNuke.Security.Permissions;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Modules.Definitions
using System.Collections;
接下来,您需要实现 IUpgradeable
功能:
public string UpgradeModule(string Version)
{
if (Version == "01.00.00")
{
// Install module permissions
InitModulePermissions();
}
return Version;
}
好的,关于 InitModulePermissions
方法的解释:
为了添加权限,我们需要一个 PermissionController
。
private void InitModulePermissions()
{
PermissionController permCtl = new PermissionController();
}
要添加权限,我们需要调用 PermissionController
的 AddPermission
方法,该方法接受一个 PermissionInfo
对象作为参数。所以,现在我们有了:
private void InitModulePermissions()
{
PermissionController permCtl = new PermissionController();
try
{
PermissionInfo pi = new PermissionInfo();
permCtl.AddPermission(pi);
}
catch{}
}
当然,一个空的 PermissionInfo
对象对任何人都没有用。这时,值得稍微绕道看一下 DNN 中的 Permission 表:
这就是我们需要提供的信息。Permission Code 标识哪些模块设置将受到影响。此代码也可用于稍后检索权限(您将看到……)。Permission Key 顾名思义,就是一个键值,而 Permission Name 是将在设置页面上显示的名称。这三个值由您定义,如下所示:
private void InitModulePermissions()
{
PermissionController permCtl = new PermissionController();
try
{
PermissionInfo pi = new PermissionInfo();
pi.PermissionCode = "PERMISSIONTEST";
pi.PermissionKey = "PERMISSION1";
pi.PermissionName = "A custom permission";
permCtl.AddPermission(pi);
}
catch{}
}
ModuleDefID
有点棘手。每个模块的 ModuleDefID
都存储在 ModuleDefinitionInfo
对象中。这可以通过 ModuleDefinitionController
的 GetModuleDefinitionByName()
方法检索。但是……
GetModuleDefinitionByName()
除了模块名称外,还需要 DesktopModuleID
,该 ID 存储在 DesktopModuleInfo
对象中。而该对象可以通过另一个控制器 DesktopModuleController
来访问。这给我们留下了以下代码:
private void InitModulePermissions()
{
PermissionController permCtl = new PermissionController();
DesktopModuleController desktopMod = new DesktopModuleController();
DesktopModuleInfo desktopInfo =
desktopMod.GetDesktopModuleByModuleName("PermissionTest");
ModuleDefinitionController modDef = new ModuleDefinitionController();
ModuleDefinitionInfo modDefInfo =
modDef.GetModuleDefinitionByName(desktopInfo.DesktopModuleID,
"PermissionTest");
try
{
PermissionInfo pi = new PermissionInfo();
pi.ModuleDefID = modDefInfo.ModuleDefID;
pi.PermissionCode = "PERMISSIONTEST";
pi.PermissionKey = "PERMISSION1";
pi.PermissionName = "A custom permission";
permCtl.AddPermission(pi);
}
catch{}
}
呼。
注意: GetModuleDefinitionByName()
接受两个参数:Desktop Module ID 和视图控件的友好名称。因此,如果您的模块的友好名称与模块名称不同,或者您正在开发一个具有多个定义的模块,请确保使用正确的名称……
但是,(目前)就这些了。在此新方法的开头设置一个断点,以调试模式运行您的 DNN 站点,单击新模块上的按钮,然后查看您的作品的效果。当此方法完成时,如果查看 Permission 表,您应该会看到新条目,并且查看模块的设置,您应该会看到一个新的复选框列……
步骤 3:封装权限
到目前为止的代码使用了许多魔术字符串 - 通常被认为实用性不如巧克力炒锅。更好的解决方案是将安全功能封装在一个特殊类中。所以,在 App_Code 目录中,创建一个新类 ModuleSecurity
,并将您需要的字符串声明为常量:
public class ModuleSecurity
{
// Constants
public const string PERMISSIONCODE = "PERMISSIONTEST";
public const string PERMISSION1 = "PERMISSION1";
}
现在,您可以使用这些常量来更改您的 try()
块:
try
{
PermissionInfo pi = new PermissionInfo();
pi.ModuleDefID = modDefInfo.ModuleDefID;
pi.PermissionCode = ModuleSecurity.PERMISSIONCODE;
pi.PermissionKey = ModuleSecurity.PERMISSION1;
pi.PermissionName = "A custom permission";
permCtl.AddPermission(pi);
}
步骤 4:实现基于权限的功能
好的,将自定义权限添加到模块设置页面都很好,但是如果没有实际检查权限的方法,无论您有什么邪恶的意图,这都是没有意义的。所以,让我们为我们的模块添加一些额外的功能 - 一个秘密消息(哇……)。只需在视图控件中添加一个 Label
,设置一些文本,并将 Visibility
设置为 False
。
<asp:label id=Label1 Visible="False" Text="My Secret Message" runat="server"></asp:label>
接下来,我们需要修改 ModuleSecurity
类,以便我们能够检索权限。我们可以通过 ModulePermissionController
获取每个单独模块的权限,但是……
ModulePermissionController
的 HasModulePermission()
方法需要一个 ModulePermissionCollection
,该集合可以通过 ModuleInfo
类检索,每个模块都继承了该类,类似于其 ModuleID
。所以,如果我们想检查模块的权限,我们需要将其 ModuleInfo
传递给我们的 ModuleSecurity
类的构造函数。我们还需要为每个权限创建一个私有成员,以及一种检索它的方法。这样就构成了完整的 ModuleSecurity
类:
public class ModuleSecurity
{
// Constants
public const string PERMISSIONCODE = "PERMISSIONTEST";
public const string PERMISSION1 = "PERMISSION1";
// private variables
private bool _permission1;
public ModuleSecurity(ModuleInfo moduleInfo)
{
ModulePermissionCollection permCollection = moduleInfo.ModulePermissions;
_permission1 =
ModulePermissionController.HasModulePermission(permCollection, PERMISSION1);
}
public bool HasPermission1
{
get { return _permission1; }
}
}
假设我们想基于权限显示新的 Label
。这意味着在视图控件的 Page_Load
事件中添加以下行:
ModuleSecurity ms = new ModuleSecurity(this.ModuleConfiguration);
Label1.Visible = ms.HasPermission1;
就这样。在页面上添加几个测试模块,为不同的用户组分配不同的权限,然后看看标签的可见性如何根据每个模块的权限而变化……
尾声:双重保险
如果您查看一些使用自定义权限的标准 DNN 模块(例如 User Defined Table),您会发现它们会在添加新权限之前检索并检查现有权限。现在,当我尝试通过多次单击按钮来添加冗余权限时,并没有发生什么异常情况,也就是说,权限表并没有突然为每个权限生成多个条目。但是,如果您想确保安全,最好还是加上这个小小的检查 - 它并没有那么复杂。我将为您提供完整的源代码;更改很简单,我相信您会自己解决的……
private void InitModulePermissions()
{
PermissionController permCtl = new PermissionController();
DesktopModuleController desktopMod = new DesktopModuleController();
DesktopModuleInfo desktopInfo =
desktopMod.GetDesktopModuleByModuleName("PermissionTest");
ModuleDefinitionController modDef = new ModuleDefinitionController();
ModuleDefinitionInfo modDefInfo =
modDef.GetModuleDefinitionByName(desktopInfo.DesktopModuleID,
"PermissionTest");
ArrayList arr =
permCtl.GetPermissionByCodeAndKey(ModuleSecurity.PERMISSIONCODE, "");
bool bPermission1=false;
foreach (PermissionInfo p in arr)
{
if ((p.PermissionKey == ModuleSecurity.PERMISSION1)&&
(p.ModuleDefID == modDefInfo.ModuleDefID))
bPermission1 = true;
}
try
{
PermissionInfo pi = new PermissionInfo();
pi.ModuleDefID = modDefInfo.ModuleDefID;
if(!bPermission1)
{
pi.PermissionCode = ModuleSecurity.PERMISSIONCODE;
pi.PermissionKey = ModuleSecurity.PERMISSION1;
pi.PermissionName = "A custom permission";
permCtl.AddPermission(pi);
}
}
catch{}
}