应用程序该如何拥抱变化
在这个原型上,“Business Addin”即业务插件,是开发者需要设计的业务模块,这个业务模块将使用权限控制服务来实现权限的控制;权限服务分为契约和不同的提供商两部分,服务提供商对于业务插件来说是透明的,这些服务提供商可能是:(1)简单的权限控制服务提供商;(2)基于MemberShip的权限控制服务提供商;(3)基于角色的访问控制权限服务提供商;(4)其它服务提供商。不管开发者从插件工厂获得了哪个服务提供商,他都能够使用一致的模型来使用权限控制服务,并且这些权限控制服务能够与.NET现有的安全机制兼容。“Business Addin”使用权限服务的场景如下,我们希望尽可能使权限控制服务与开发者无关并且简单可重用。
“Business Addin”业务插件使用一般场景如下:
{
// 当前用户拥有Id为“PermissionId”的权限,因此允许执行以下操作
}
else
{
// 向用户提示,您没有此操作的权限,请联系管理员给予分配“PermissionName”权限
}
这样对于开发者的好处是显而易见的:(1)开发者也开发业务系统过程中不再需要设计任何的用户-角色-权限管理的应用模块;(2)开发者可以根据需要任意定义/扩展业务插件所需的权限,这些权限的管理最终由插件工厂里的权限服务提供商来实现。
下面我们看一下相关的项目及服务定义。
运行效果图如下。在这里,我们为应用系统安装了SimplePermissionService,那么IPermissionService的提供商就是SimplePermissionService。如果用户需要其它的实现,比如ASP.NET MemberShipe实现的权限控制,就可以下载相应的插件来提供权限服务,但这对业务插件来说是透明的,它不需要做任何的代码变更。
权限服务定义如下。
{
/// <summary>
/// Common permission service. It needs to be compitble with .NET Security Model which consists of
/// IIdentity, IPrincipal and IPermission.
/// </summary>
public interface IPermissionService
{
/// <summary>
/// If user addin uses [AddinPermission("PermissionId", "Name")] to define a permission
/// within the business addin, the permission service will inject the default permission
/// instance into it.
/// </summary>
Type DefaultPermissionType { get; }
/// <summary>
/// Get the authenticated principal. The principal will provide current user identity and
/// the roles of current user.
/// </summary>
IPrincipal User { get; set; }
/// <summary>
/// Create a new default permission instance.
/// </summary>
/// <returns>The new default permission instance.</returns>
IPermission CreateDefaultPermission();
/// <summary>
/// Demand whether current user owns the specified permission in current addin.
/// </summary>
/// <param name="permissionId">The permission id.</param>
/// <returns>If owns, return true, otherwise return false.</returns>
bool Demand(string permissionId);
/// <summary>
/// Demand whether current user owns the specified permission in specified addin.
/// </summary>
/// <param name="addinId">The addin which define the specified permission.</param>
/// <param name="permissionId">The permission id.</param>
/// <returns>If owns, return true, otherwise return false.</returns>
bool Demand(string addinId, string permissionId);
/// <summary>
/// Demand whether current user owns the specified permission in specified addin.
/// </summary>
/// <param name="addin">The addin which define the specified permission.</param>
/// <param name="permissionId">The permission id.</param>
/// <returns>If owns, return true, otherwise return false.</returns>
bool Demand(Addin addin, string permissionId);
/// <summary>
/// Demand whether current user owns the specified permission in specified addin.
/// </summary>
/// <param name="addin">The addin which define the specified permission.</param>
/// <param name="permissionId">The permission id.</param>
/// <returns>If owns, return true, otherwise return false.</returns>
bool Demand(RuntimeAddin addin, string permissionId);
}
}
[assembly: AddinPermission("Guest", "Guest Permission", typeof(CustomizedPermission))]
(2)获取权限服务并请求验证权限
Context.GetFirstOrDefaultService<IPermissionService>();
if (permissionService != null)
{
if (permissionService.Demand("MyPermissionId"))
{
Response.Write("Permission demanded successfully. <br />");
}
else
{
Response.Write("Permission demanded failed. <br />");
}
}
else
{
Response.Write("Please install a Permission Service Provider first.");
}
这个拥抱变化的思想是基于面向服务架构思想来实现的,在这里,“服务=契约 + 实现,契约=面向对象中的接口,实现=实现接口的类型”。业务插件依赖的是服务的契约,并不依赖服务的实现,服务的实现针对契约的不同提供商。我们可以根据应用系统的需要,在不更改业务插件的情况下,变更服务提供商来满足实际系统的需求。