论坛演示地址:http://www.entityspider.com/
源代码下载地址:http://files.cnblogs.com/netfocus/Forum.rar
蜘蛛侠论坛采用Forms验证方式。
1: 当用户输入用户名和密码并登陆, 此时, 我们会将当前用户的身份标识保存到客户端:
文件:
\Core\Managers\MemberManager.cs
代码:
CookieManager.AddCookieToResponse(
FormsAuthentication.GetAuthCookie(member.MemberId.Value.ToString(),
false
), expireDays);
2: 用户登陆后, ASP.NET下次就自动知道当前访问用户的身份标识了. 我们可以通过如下方式获取当前登陆用户的标识:
HttpContext.Current.User.Identity.Name
另外, 如何判断一个用户是否处于登陆状态? 我们可以通过如下的方式来判断:
HttpContext.Current.Request.IsAuthenticated
如果该属性返回TRUE,则表示当前用户已登陆,否则,表示未登陆。
3: 在什么时候获取当前用户的所有信息?
ASP.NET提供了一个时机,让我们对用户执行身份验证。该时机就是Application对象的AuthenticateRequest事件。所以,我们可以在该事件的处理函数中确定当前访问用户是否已经登陆,
文件:
\Core\Components\Common\HttpModule.cs
代码:
private
void
Application_AuthenticateRequest(Object source, EventArgs e)
{
HttpRequest request
=
HttpContext.Current.Request;
if
(request.Url.LocalPath.ToLower().EndsWith(
"
.aspx
"
)
||
request.Url.LocalPath.ToLower().EndsWith(
"
.ashx
"
))
{
SetCurrentUser();
}
}
private
void
SetCurrentUser()
{
if
(
!
HttpContext.Current.Request.IsAuthenticated)
{
HttpContext.Current.User
=
UserManager.GetAnonymousUser();
}
else
{
try
{
User user
=
UserManager.GetUser(
new
Guid(HttpContext.Current.User.Identity.Name));
if
(user
!=
null
)
{
HttpContext.Current.User
=
user;
}
else
{
MemberManager.Logout();
HttpContext.Current.User
=
UserManager.GetAnonymousUser();
}
}
catch
{
MemberManager.Logout();
HttpContext.Current.User
=
UserManager.GetAnonymousUser();
}
}
}
大家可以看到,我们在AuthenticateRequest事件的处理函数中确定一个当前用户,SetCurrentUser函数实现该功能。该函数首先判断当前用户是否已经登陆,如果未登陆,则获取一个匿名用户对象,并赋值给HttpContext.Current.User;如果已经登陆,则根据用户标识从数据库获取登陆用户对象,并同样把该用户对象赋值给HttpContext.Current.User;这里有一个很关键的问题,我们为什么可以把当前获取的用户对象赋值给HttpContext.Current.User?其实很简单,我们只要让我们自己定义的User类实现IPrinciple接口即可,User类的代码如下:
public
class
User : Entity, IPrincipal
{
private
IIdentity identity
=
null
;
#region
Implementation of IPrincipal
public
IIdentity Identity
{
get
{
return
identity;
}
set
{
identity
=
value;
}
}
public
bool
IsInRole(
string
roleName)
{
//
Return true or false by your own logic.
return
false
;
}
#endregion
}
这里我为了突出重点,所以把User类的其他不相关的东西删除了。大家可以看到,我们只要让User类实现IPrinciple接口就行了。然后我们可以为User类包含很多我们自定义的属性。
这样的做法有什么好处呢?其实我们也完全可以把当前用户放在Session或Cache等其他地方。我觉得最大的好处就是自然,因为ASP.NET提供给我们的HttpContext.Current.User对象的意图就是表示当前发送请求的用户实例,但因为该对象所存储的信息非常少,基本上就只存放了一个标识当前登陆用户的标识(如用户名)。但大部分情况下,我们都需要更多的用户信息,所以就自然而然很容易想到扩展该User属性。
当然还有一个需要说明的细节是,
因为我们自己创建了一个新的User对象,并且赋值给了HttpContext.Current.User,而赋值之前,HttpContext.Current.User.Identity不为空,所以为了一致,我们也应该给我们自己定义的User类的Identity属性赋值。
文件:
\Core\UserRolePermissions\User.cs
代码:
public
static
User GetAnonymousUser()
{
User user
=
Activator.CreateInstance(Configuration.Instance.UserType)
as
User;
user.SetRoles(Configuration.Instance.AnonymousDefaultRoleList);
user.Identity
=
new
GenericIdentity(
string
.Empty);
return
user;
}
public
static
User GetUser(Guid memberId)
{
TRequest
<
User
>
request
=
new
TRequest
<
User
>
();
request.Data
=
Activator.CreateInstance(Configuration.Instance.UserType)
as
User;
request.Data.MemberId.Value
=
memberId;
EntityList users
=
Engine.GetAll(request);
User user
=
null
;
if
(users.Count
>
0
)
{
user
=
users[
0
]
as
User;
}
if
(user
!=
null
)
{
InitializeUser(user);
}
return
user;
}
private
static
void
InitializeUser(User user)
{
if
(user
!=
null
)
{
TEntityList
<
Role
>
roles
=
new
TEntityList
<
Role
>
();
foreach
(UserAndRole userAndRole
in
RoleManager.GetUserRoles(user.EntityId.Value))
{
roles.Add(userAndRole.Role);
}
user.SetRoles(roles);
user.Identity
=
HttpContext.Current.User.Identity;
}
}
大家可以看到黄色高亮度显示的那几行代码,我对Identity属性进行了赋值。
4: 如何在页面中访问当前用户?
文件:
\Business\Controls\ForumUserControl.cs
代码:
public
class
ForumUserControl : BaseUserControl
{
protected
ForumUser CurrentUser
{
get
{
return
HttpContext.Current.User
as
ForumUser;
}
}
protected
bool
ValidatePermission(PermissionType permission)
{
return
CurrentUser.GetPermissions().ValidatePermission((
long
)permission);
}
protected
bool
ValidatePermission(PermissionType permission, Entity entity)
{
return
CurrentUser.GetPermissions(entity).ValidatePermission((
long
)permission);
}
}
ForumUserControl是一个基类UserControl,我们可以在该控件中提供一个表示当前登陆用户的属性CurrentUser,这样一来,我们在各个地方就可以很容易的访问我们自定义好的用户对象啦。是不是很简单呢?
好了, 以上就是蜘蛛侠论坛中当前登陆用户的设计与实现。因为觉得可能对大家有用,所以写出来与大家分享。