Community Server
专题十:
MemberRole
之
RoleManager
由于最近忙于一些琐事,近半个月都没有写新的专题,今天忙里抽闲赶紧补上,实在是抱歉。
设计做多了就会发现,用户权限管理是一个永恒的话题,几乎没有什么项目不需要权限和角色管理的,可能会无数次去写角色管理的代码,而且会根据项目的不同粒度也会有所不同。在
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 下:
private void OnEnter( object source, EventArgs eventArgs)
{
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 等机制。