为简单计,本文只讨论在服务器端的用户身份验证。登录页面是通过调用ASPSecurity.inc中的signUserOn函数验证用户身份的。signUserOn检查数据库中是否存在和用户输入的名字、密码匹配的记录:
function signUserOn(aSignon, aPassword)
dim dict
' 用户输入的名字
aSignon = lcase(trim(aSignon))
' 用户输入的密码
aPassword = lcase(trim(aPassword))
' 提取用户记录转换成Dictionary对象
set dict = getUser(aSignon)
' dict对象是否包含了合法的用户信息
if isUser(dict) then
if not dict("Password") = aPassword then
signUserOn = false
Session("msg") = "密码错误."
exit function
end if
' 更新最后访问时间
call updateLastOn(aSignon)
' 用SessionID (或不支持Cookies时,ID)标识用户记录
if not Session("SupportsCookies") then
Session("ID") = getID()
dict.Add "SessionID", Session("ID")
else
dict.Add "SessionID", Session.SessionID
end if
' 记录最后活动时间
dict.add "LastActivity", now()
' 在Session中记录当前用户信息
set Session("User") = dict
' 将当前用户加入正在访问用户列表
call addUserToApplication(dict)
signUserOn = true
else
Session("msg") = "用户名称错误"
signUserOn = false
end if
end function
如果用户输入的名字和密码与数据库中的记录匹配,signUserOn函数返回True。此时,用户被授权,Session("User")变量包含了一个Dictionary对象,其中含有该用户的数据库记录的字段名称和值。另外,这里还把Dictionary对象加入到Application("User")数组,这是为了便于获得当前正在访问安全站点的用户清单。 signUserOn用到了ASPSecurity.inc中的许多子过程。由于大多数子过程都很相似,下面只讨论其中的getUser。该函数先连接数据库,然后提取对应的用户记录,最后将记录转换为Dictionary对象并返回它,如下所示:
function getUser(aSignon)
dim conn
dim R
set conn = openConnection()
set R = conn.Execute("SELECT * FROM Users WHERE Users.Signon='" &
aSignon & "'")
if err.number < > 0 then
' 输出错误信息
......
response.end
end if
if not R.EOF then
set getUser = recordToDictionary(R)
else
set getUser = nothing
end if
R.Close
set R = nothing
conn.close
set conn = nothing
end function
如果用户在注册页面中单击的是注册按钮,则在经过必要的检查之后就可以在数
据库中生成新的用户记录了。注册成功的用户会自动进入安全页面,这一部分操作和
普通的登录过程是一样的。
身份验证和注册操作都将错误信息存储在Session("msg")变量中。这些错误信
息可以显示在返回给用户的HTML页面中:
< %
if Session("msg") < > "" then
' 显示错误信息
......
Session("msg") = ""
end if
%>
在安全页面中检查是否已经验证用户身份
每一个受保护的页面都应该检查用户身份是否已经验证。这是因为用户有可能为
这些页面做了书签,如果不在这些页面中验证用户已经登录,就不能保证浏览页面的
是经过授权的合法用户。
为检查是否已经验证用户身份,可以测试在signUserOn中创建的Session("User")是否是一个对象、类型是否正确等。如果上述测试失败,则重定向浏览器到
登录页面signOn.asp。对于不支持Cookies的浏览器,检查用户是否经过身份验证的方法略为复杂,它需要通过在Application("Users")中搜索ID获得当前用户记录。如下面的代码在signedOn页面中完成上述检验:
< %@ Language=VBscript %>
< % option explicit %>
< % Response.Buffer = true %>
< % Response.Expires = 0 %>
< !-- #INCLUDE FILE="ASPSecurity.inc" -->
< HTML>
< BODY>
< %
dim ID
dim aUser
dim AppUsers
dim authenticated
dim I
if Session("SupportsCookies") then
if not isUser(Session("User")) then
Response.Redirect "signon.asp"
else
set aUser = Session("User")
end if
else
authenticated = false
ID = Request("ID")
if len(ID) > 0 then
AppUsers = Application("Users")
for each aUser in AppUsers
if aUser("SessionID") = ID then
authenticated=true
aUser("LastActivity") = now()
Application.Lock
Application("Users") = AppUsers
Application.UnLock
exit for
end if
next
end if
if not authenticated then
Response.Redirect "signon.asp"
end if
end if
%>
会话终止
当ASP会话结束时会运行global.asa中的Session_OnEnd方法,可以在这里删除
保存在Application("Users")数组中由于超时而被终止会话的用户。记录用户是由于什么原因(超时还是显式退出)终止会话往往很有用处,下面的代码通过更新Users表的TimedOut字段实现该功能:
sub Session_OnEnd
dim AppUsers
dim aUser
dim I
dim j
dim conn
dim supportsCookies
dim foundUser
on error resume next
supportsCookies=Session("SupportsCookies")
Application.Lock
AppUsers = Application("Users")
foundUser = false
for I = 0 to ubound(AppUsers)
set aUser = AppUsers(I)
if supportsCookies then
if aUser("SessionID") = Session.SessionID then
foundUser = true
end if
elseif dateAdd("n", Session.timeout, aUser("LastActivity")) < now()
then
foundUser = true
end if
if foundUser then
set conn = server.createObject("ADODB.Connection")
conn.ConnectionString=Session("ConnectionString")
conn.ConnectionTimeout=Session("ConnectionTimeout")
conn.mode=Session("Mode")
conn.open
conn.execute "UPDATE Users SET TimedOut=1 WHERE Users.Signon='" &
aUser("Signon") & "'"
conn.close
set conn=nothing
set aUser=nothing
set AppUsers(I) = nothing
for j = I to ubound(AppUsers) - 1
set AppUsers(j) = AppUsers(j + 1)
next
if ubound(AppUsers) > 0 then
redim preserve AppUsers(ubound(AppUsers) - 1)
else
AppUsers = Array()
end if
exit for
end if
next
Application("Users") = AppUsers
Application.UnLock
end sub