由于最近忙于一些琐事,近半个月都没有写新的专题,今天忙里抽闲赶紧补上,实在是抱歉。
设计做多了就会发现,用户权限管理是一个永恒的话题,几乎没有什么项目不需要权限和角色管理的,可能会无数次去写角色管理的代码,而且会根据项目的不同粒度也会有所不同。在CS中,采用了MemberRole.dll中的RoleManager进行角色管理,该角色管理机制同样在asp.net 2.0 beta2 中得到应用。在分析代码之前先看看数据库中的角色的关系表:
表分两种前缀,一种是“aspnet_”另一种是“cs_”,“aspnet_”是采用MemberRole.dll组件所必需的一些表,包括过程和视图等都是这样命名的,在asp.net 2.0 beta2 中你也可以看到同样的表、视图与储存过程。“cs_”前缀是CS系统需要的表,由此可以看到MemberRole.dll中的RoleManager只 管理到角色级别,通常我们还会给角色添加一些权限,然后在应用系统中判断角色拥有的权限从而决定用户是否有访问的权限,当然一个用户可以有多个角色,一个 角色又可以有多个权限。有时你设计的某些系统是不需要做如此多权限管理的,只要多个角色就可以解决问题,那么就不再需要扩展数据库,直接使用MemberRole.dll中的RoleManager就可以了。
注意:你可能会对cs_SectionPermissions、cs_ProductPermissions表产生疑惑,这里有两个权限表,分别管理两种权限,cs_SectionPermissions中存储节点级别的权限,如Blog中,是否有权限开通blog,管理所有blog等,这些权限就放在cs_SectionPermissions,但是对于每个blog,如我的blog,现在不想要某个用户访问,或者需要某个用户帮忙管理,再或者某个地方某些用户可以访问,某些不行,这样的权限就放入cs_ProductPermissions中设置。
RoleManager是一个HttpModule,由此可以在web.config中看到如下的配置文件:
这也是RoleManager角色管理的入口点,同时,在RoleManager中实现了IConfigurationSectionHandler接口,用来读取Web.config中的以下配置:
cacheRolesInCookie="true" cookieName=".CSRoles" cookieTimeout="90"
cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true"
createPersistentCookie="true" cookieProtection="All" maxCachedResults="1000" >
<providers>
<add
name="CommunityServerSqlProvider"
type="CommunityServer.Components.CSRoleProvider, CommunityServer.Components"
connectionStringName="SiteSqlServer"
applicationName="dev"
description="Stores and retrieves roles data from the local Microsoft SQL Server database"
/>
</providers>
</roleManager>
再这里我们又看到了Provider模型,其实asp.net 2.0 beta2中大量使用了这种数据访问模型。它的优点我在前面的专题中已经讲解过,不理解的朋友可以看我之前的专题。
在RoleManager很重要的一个类就是:
该类继承至IPrincipal,因此我们可以在用户登录后通过检查当前Context中User的一些方法和属性,判断拥护是否拥有某角色。操作的方法在RoleMangerModule类下的OnEnter下:
{
if (Roles.Enabled)
{
HttpContext context1 = ((HttpApplication) source).Context;
if (context1.User == null)
{
context1.User = new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
}
if (this._eventHandler != null)
{
RoleManagerEventArgs args1 = new RoleManagerEventArgs(context1);
this._eventHandler(this, args1);
if (args1.RolesPopulated)
{
return;
}
}
if (Roles.CacheRolesInCookie)
{
if (context1.User.Identity.IsAuthenticated && (!Roles.CookieRequireSSL || context1.Request.IsSecureConnection))
{
try
{
HttpCookie cookie1 = context1.Request.Cookies[Roles.CookieName];
if (cookie1 != null)
{
string text1 = cookie1.Value;
if ((text1 != null) && (text1.Length > 0x1000))
{
Roles.DeleteCookie();
}
else
{
if (((Roles.CookiePath != null) && (Roles.CookiePath.Length > 0)) && (Roles.CookiePath != "/"))
{
cookie1.Path = Roles.CookiePath;
}
cookie1.Domain = Roles.Domain;
context1.User = new RolePrincipal(context1.User.Identity, text1);
}
}
}
catch
{
}
}
else if (context1.Request.Cookies[Roles.CookieName] != null)
{
Roles.DeleteCookie();
}
}
if (!(context1.User is RolePrincipal))
{
context1.User = new RolePrincipal(context1.User.Identity);
}
}
}
由于知识点比较简单, 在MSDN上也有相关的IPrincipal与Identity的介绍,我就不细细的分析。
在RoleManger里,很多地方使用了Cookie,这样做提高了不少的效率,你想,如果每个用户每次访问一个页面都去读一次数据库,把该访问用户的权限读取出来,也许你聪明点,把该用户的权限先缓存在内存中,并且设置一定的过期时间,其实你还能再聪明一点,那就是把角色保存在客户端的Cookie,这样连服务器的内存都节约了。只有在用户第一次登录,或者清除了Cookie等Cookie失效的情况下才需要访问数据库。但是这也带来一个问题,就是如果客户端禁止使用Cookie,用户将无法正常访问。CS中通过在web.config中可以配置是否启用这种机制。
到这里,整个MemberRole.dll算是粗略的讲解了一遍,由于时间上的限制不可能满足所有读者的要求,如果有疑问可以msn我或者给我留言。后面一些专题我将说说CS的页面,包括MasterPage、Theme、Skin等机制。