admin管理员组

文章数量:815885

令牌桶生成令牌

令牌桶生成令牌

This demonstration started out as a follow up to some recently posted questions on the subject of logging in: .html and .html. The Asker was originally trying to find a way to eliminate the scenario where his users are staring at the screen thinking and writing only to click the submit button and find out that they were logged out and their updates are lost.

该演示首先是对最近发布的有关登录主题的一些问题的跟踪: http: //www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28634665.html和http:// www。 expert-exchange.com/Programming/Languages/Scripting/ASP/Q_28641013.html 。 Asker最初试图找到一种方法来消除这种情况,即他的用户盯着屏幕进行思考和写作,只是单击“提交”按钮并发现他们已注销并且更新丢失。

I know many people may try adjusting the script timeout or the session timeout only to find this does not work as expected. The reason is they forget about the idle timeout that is set to the default of 5 minutes in IIS: =ws.10%29.aspx

我知道很多人可能会尝试调整脚本超时或会话超时,只是发现这无法按预期工作。 原因是他们忘记了IIS中设置为5分钟默认值的空闲超时: https : //technet.microsoft.com/zh-cn/library/cc771956%28v=ws.10%29.aspx

Simply adjusting the idle timeout to something longer coupled with adjusting your session.timeout=60 (for 60 minutes) is not the best solution. Session variables can be reset if the app pool recycles or crashes:

简单地将空闲超时调整为更长的时间再调整会话。timeout= 60(60分钟)不是最佳解决方案。 如果应用程序池回收或崩溃,则可以重置会话变量: http : //weblogs.asp.net/owscott/why-is-the-iis-default-app-pool-recycle-set-to-1740-minutes

An alternative is to issue a new and unique token at each log in. Then set a cookie using the generated token as well as storing the token in a user table in your database. On each page load, look up the cookie with the token, and look for a match in the user login table. If a match is found, test if the expiration date is valid. When everything checks out, give access to the page.

一种替代方法是在每次登录时发出一个新的唯一令牌。然后使用生成的令牌设置cookie,并将该令牌存储在数据库的用户表中。 在每次页面加载时,请使用令牌查找cookie,然后在用户登录表中查找匹配项。 如果找到匹配项,则测试到期日期是否有效。 一切都检查完后,请访问该页面。

I have created a more detailed sample using this process that also allows for user levels. This demonstration is intended to show the process and is not meant to be a production-ready login system.

我使用此过程创建了一个更详细的示例,该示例也允许用户使用。 该演示旨在显示过程,而不是成为可用于生产的登录系统。

I am using MSSQL SERVER 2012 with two tables and one view. The first table is a users table where I am storing the user's name, email, hashed password and user level.

我正在使用具有两个表和一个视图的MSSQL SERVER 2012。 第一个表是一个用户表,其中存储了用户名,电子邮件,哈希密码和用户级别。

The second table is the login transaction table where I store the tokens with a user id, the token expiration, the IP used to log in and and the timestamp of the log in. I have the field LoggedTimeStamp set to the current date/time using getdate().

第二个表是登录事务表,我在其中存储带有用户ID的令牌,令牌到期,用于登录的IP和登录的时间戳。使用以下命令将LoggedTimeStamp字段设置为当前日期/时间: getdate()。

The view of logged in users selects rows of data from the Log In Trans table where the TokenExpires is greater than the current timestamp and the token field is not blank.

已登录用户的视图从Log In Trans表中选择数据行,其中TokenExpires大于当前时间戳,并且token字段不为空。

CREATE TABLE [dbo].[ee_tUsers]([ID] [int] IDENTITY(1,1) NOT NULL,[FirstName] [nvarchar](50) NULL,[LastName] [nvarchar](50) NULL,[Email] [nvarchar](150) NULL,[UserName] [nvarchar](50) NULL,[Password] [nvarchar](350) NULL,[UserLevel] [nvarchar](50) NULL
) ON [PRIMARY]CREATE TABLE [dbo].[ee_tLoginTrans]([ID] [int] IDENTITY(1,1) NOT NULL,[UserID] [int] NULL,[UserName] [nvarchar](50) NULL,[Token] [nvarchar](350) NULL,[TokenExpires] [datetime] NULL,[LoggedIP] [nvarchar](50) NULL,[LoggedTimeStamp] [datetime] NULL,
) ON [PRIMARY]CREATE VIEW [dbo].[ee_vLoggedInUsers]
AS
SELECT dbo.ee_tLoginTrans.UserID, dbo.ee_tLoginTrans.UserName, dbo.ee_tLoginTrans.Token,         dbo.ee_tLoginTrans.TokenExpires, dbo.ee_tLoginTrans.LoggedIP, dbo.ee_tLoginTrans.LoggedTimeStamp, dbo.ee_tUsers.UserLevelFROM dbo.ee_tUsers RIGHT OUTER JOINdbo.ee_tLoginTrans ON dbo.ee_tUsers.ID = dbo.ee_tLoginTrans.UserIDWHERE(dbo.ee_tLoginTrans.TokenExpires > GETDATE()) AND (dbo.ee_tLoginTrans.Token <> N'') 

A side benefit of using a log in transaction table like this is you can run a report of who logged in with the time stamp and IP.  You can also view the current list of logged in users and if you like, remove their token and thus logging them out.

使用这样的登录事务表的一个附带好处是,您可以生成有关谁使用时间戳和IP登录的报告。 您还可以查看当前登录用户列表,如果愿意,可以删除其令牌并注销。

The three flow charts below shows the process of logging in, creating the token and testing authentication on each page.

下面的三个流程图显示了登录,创建令牌以及在每个页面上测试身份验证的过程。





The file structure I am using in this demo uses an includes folder where I have a config.asp, functions.asp and nav.asp.

我在此演示中使用的文件结构使用一个include文件夹,其中包含config.asp,functions.asp和nav.asp。

The config.asp is used to store my database connection and other variables such as the amount of time to be logged in and a secret key used in the hashing functions.

config.asp用于存储数据库连接和其他变量,例如登录时间和哈希函数中使用的密钥。

The Functions.asp is used to store functions I will use on multiple pages such as sha256, setting passwords, setting the token, looking up the token.

Functions.asp用于存储我将在多个页面上使用的函数,例如sha256,设置密码,设置令牌,查找令牌。

The nav.asp are the navigation links.

nav.asp是导航链接。

The first step is to create the two tables and view. Make sure the LoggedTimeStamp field in the ee_tLoginTrans table will default to the current date/time.

第一步是创建两个表和视图。 确保ee_tLoginTrans表中的LoggedTimeStamp字段将默认为当前日期/时间。

You will have to make some adjustments in your code. For my own testing, I have placed the files in a sub folder of one of my domains and you may see code to include a file like . It is important you adjust the path to where you actually store the files. If your includes folder is at the top level of the site, then change to . Note that I could have simply used but purposely didn't. In order to use that method, you would need to have parent paths turned on in IIS and that is a security risk. I see a lot of videos and tutorials demonstrating how to turn parent paths off because it is easier to migrate your old code, but don't do this.

您将不得不在代码中进行一些调整。 为了进行我自己的测试,我将文件放在了我的一个域的子文件夹中,您可能会看到包含这样的文件的代码。 调整实际存储文件的路径非常重要。 如果您的include文件夹位于网站的顶层,则更改为。 请注意,我本可以简单使用,但故意不使用。 为了使用该方法,您需要在IIS中打开父路径,这存在安全风险。 我看到很多视频和教程演示了如何关闭父路径,因为这样可以更轻松地迁移旧代码,但不要这样做。

Next, add the pages that will go on the main level

接下来,添加将在主级别上显示的页面

INDEX.ASP

索引文件

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" -->
<%
if request.form("username")<>"" then
dim cmd,rsSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "SELECT ID, UserName,UserLevel, Password FROM dbo.ee_tUsers WHERE Username = ?" cmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 350, request.form("username")) 'stringcmd.Prepared = trueSet rs = cmd.Executeif not rs.eof thenif passwordHash(request.form("username"),request.form("password"))=rs("password") then 'the hash's matchsetToken rs("ID"),rs("UserName") ' function to set usernameredirectLoginLevel rs("UserLevel") ' function to redirectend ifend ifrs.Close()Set rs = Nothingend if
%>
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="UTF-8">
<title>Log In</title>
</head><body><div id="login">
<h1>Log In</h1>
<form method="post" action="" autocomplete="off"><input name="username" placeholder="Username"><input name="password" type="password" placeholder="Password"><button type="submit">Submit</button>
</form>
</div>
</body>
</html> 

ADMIN.ASP

管理员程序

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" -->
<%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR logged_in_level<>"Admin" thenresponse.Redirect("index.asp")
end if
%>
<%
dim cmd,arrUsers,UserID,FirstName,LastName,Email,UserName,UserLevel,rs,i
Set cmd = Server.CreateObject ("ADODB.Command")
cmd.ActiveConnection = conEE
cmd.CommandText = "SELECT ID, FirstName,LastName,Email, UserName,UserLevel FROM dbo.ee_tUsers" 
cmd.Prepared = true
Set rs = cmd.Executeif not rs.eof thenarrUsers = rs.getrows()
end ifrs.Close()
Set rs = Nothing%><!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="UTF-8">
<title>Admin</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<h1>Admin</h1>
<h2>User List</h2>
<%
If IsArray(arrUsers) Thenresponse.write "<table class='usertable'>"response.write "<tr><th>Edit</th><th>First</th><th>Last</th><th>Level</th></tr>"For i = LBound(arrUsers, 2) To UBound(arrUsers, 2)UserID 			= arrUsers(0, i) ' order based on sql statment,  ID, FirstName,LastName,Email, UserName,UserLevel FirstName 	= arrUsers(1, i)LastName 	= arrUsers(2, i)Email			= arrUsers(3, i)UserName	= arrUsers(4, i)UserLevel 	= arrUsers(5, i)response.write "<tr><td><a href='userEdit.asp?userid="&UserID&"'>Edit</a></td><td>"&FirstName&"</td><td>"&LastName&"</td><td>"&UserLevel&" </td></tr>"		Nextresponse.write "</table>"End If 
%></body>
</html> 

LOGGEDINUSERS.ASP

LOGGEDINUSERS.ASP

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" -->
<%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR logged_in_level<>"Admin" thenresponse.Redirect("index.asp")
end if
%>
<%
dim cmd,arrUsers,UserID,UserName,IP,LogInTime,TokenExpires,UserLevel,rs,i,logoutformif request.form("logoutuser")<>"" thenif isnumeric(request.form("logoutuser")) thenlogOutToken(request.form("logoutuser"))end if
end ifSet cmd = Server.CreateObject ("ADODB.Command")
cmd.ActiveConnection = conEE
cmd.CommandText = "SELECT UserID, UserName, Token, TokenExpires, LoggedIP, LoggedTimeStamp, UserLevel FROM ee_vLoggedInUsers" 
cmd.Prepared = true
Set rs = cmd.Executeif not rs.eof thenarrUsers = rs.getrows()
end ifrs.Close()
Set rs = Nothing%><!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="UTF-8">
<title>Admin</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<h1>Admin</h1>
<h2>User List</h2>
<%
If IsArray(arrUsers) Thenresponse.write "<table class='usertable'>"response.write "<tr><th>Log Out</th><th>User</th><th>Expires</th><th>IP</th><th>TimeStamp</th><th>Level</th></tr>"For i = LBound(arrUsers, 2) To UBound(arrUsers, 2)UserID 			= arrUsers(0, i) ' order based on sql statment,UserName 		= arrUsers(1, i)Token 				= arrUsers(2, i)TokenExpires	= arrUsers(3, i)IP						= arrUsers(4, i)LogInTime 		= arrUsers(5, i)UserLevel			= arrUsers(6, i)logoutform= "<form method='post' action=''><input type='hidden' name='logoutuser' value='"&UserID&"'><button type='submit'>Submit</button></form>"response.write "<tr><td>"&logoutform&"</td><td>"&UserName&"</td><td>"&TokenExpires&"</td><td>"&IP&" </td><td>"&LogInTime&"</td><td>"&UserLevel&" </td></tr>"		Nextresponse.write "</table>"End If 
%></body>
</html> 

SALES.ASP

销售网站

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" -->
<%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR instr("Admin Sales",logged_in_level)<1 thenresponse.Redirect("index.asp")
end if
%><!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Sales</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<h1>Sales </h1>
</body>
</html> 

SUPPORT.ASP

支持

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" -->
<%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR  instr("Support Admin",logged_in_level)<1 thenresponse.Redirect("index.asp")
end if
%>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Support</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<h1>Support</h1>
<div>This section can be seen by Support and Admin</div>
<%
if logged_in_level = "Admin" then
%>
<div>This section can be seen ONLY by Admin</div>
<%
end if
%>
</body>
</html> 

USERADD.ASP

USERADD.ASP

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" --><%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR logged_in_level<>"Admin" thenresponse.Redirect("index.asp")
end if
%>
<%
Dim rs,cmd, userid,cmdNewPassword' ---------- CREATE CONTACT -------------
if request.form("action")="createContact" thendim update_response, validation, validation_username,validation_password, cmdFirstName, cmdLastName, cmdEmail, cmdUsername, cmdLevelvalidation=0 	' set to not validatevalidation_username=1  'set to validate (in case of blank)validation_password = 1  'set to validate (in case of blank)cmdFirstName = request.form("firstname")cmdLastName = request.form("lastname")cmdEmail = request.form("email")cmdUsername = request.form("username")cmdLevel = request.form("userlevel")'------- validation --------------if len(cmdFirstName)<3 then validation=validation+1 end if ' first name should be at least 3 charactersif len(cmdLastName)<3 then validation=validation+1 end if ' last name should be at least 3 charactersif len(cmdEmail)<7 then validation=validation+1 end if ' email should be at least 7if instr(cmdEmail,"@")<1 then validation=validation+1 end if ' email should contain @ or use RegEXif len(cmdLevel)<3 then validation=validation+1 end if ' level should be at least 3 characters' check if username is uniqueif cmdUsername<>"" then ' allow blank usernamesSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "SELECT ID FROM dbo.ee_tUsers WHERE UserName = ?" cmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 50, cmdUsername) ' adDoublecmd.Prepared = trueSet rs = cmd.Executeif not rs.eof then ' the username is in use, don't updatevalidation_username=0end ifrs.Close()Set rs = Nothingend if' validate passwordcmdNewPassword = ""if request.form("newpassword")<>"" then ' try and add new passwordif validatePassword(request.form("newpassword"))= True thencmdNewPassword=request.form("newpassword")cmdNewPassword= passwordHash(cmdUsername,cmdNewPassword)elsevalidation_password=1end ifend if' -------- end validation ----------if validation = 0 AND validation_username = 1 AND validation_password = 1   then ' if no errros proceedSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "INSERT INTO dbo.ee_tUsers ( FirstName, LastName,Email, UserLevel,Username, Password) VALUES (?,?,?,?,?,?)" cmd.Prepared = truecmd.Parameters.Append cmd.CreateParameter("first", 202, 1, 50, cmdFirstName) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("last", 202, 1, 50, cmdLastName) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("email", 202, 1, 150, cmdEmail) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("level", 202, 1, 50, cmdLevel) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 50, cmdUsername) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("password", 202, 1, 350, cmdNewPassword) ' adVarWCharcmd.Executecmd.ActiveConnection.Closeupdate_response="success|User Updated"' check if username should be updatedelseupdate_response="error|You have "&validation&" errors.  Please set all fields"if validation_password = 0 thenupdate_response=update_response&"<br>Invalid Password"end ifif validation_username = 0 thenupdate_response=update_response&"<br>Username in use"end ifend if' resetcmdFirstName="" cmdLastName=""cmdEmail=""cmdUsername=""cmdLevel=""end if%><%'setPassword "password",1
%>
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="UTF-8">
<title>Contact Edit</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<%dim arrMessage,messageClass,messageContent
' if there is a form update, show mesageif update_response<>"" then ' this is delimted by a pipe class|messagearrMessage = split(update_response,"|")messageClass = arrMessage(0)messageContent = arrMessage(1)response.write "<div class='"&messageClass&"'>"&messageContent&"</div>"'response.write messageContentend if
%>
<form method="post" action=""  autocomplete="off">
<input type="hidden" name="action" value="createContact">
<input type="hidden" name="contactid">
<label>First Name</label>
<input name="firstname" >
<label>Last Name</label>
<input name="lastname" >
<label>Email</label>
<input name="email">
<label>username</label>
<input name="username"  >
<label>User Level</label>
<select name="userlevel"><option value="">No Log In</option><option value="Admin">Admin</option><option value="Support">Support</option><option value="Sales">Sales</option>
</select><p class="notice">Leave blank for no password</p>
<label>New Password</label>
<input name="newpassword">
<button type="submit">Submit</button>
</form></body>
</html> 

USEREDIT.ASP

USEREDIT.ASP

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/ee/login/includes/config.asp" -->
<!--#include virtual="/ee/login/includes/functions.asp" --><%
' ---------- test for log in and level ------------
if logged_in_status = "0" OR logged_in_level<>"Admin" thenresponse.Redirect("index.asp")
end if
%>
<%
Dim rs,cmd, userid,cmdPassword' ---------- SET USER ID FROM QUERYSTRING -------------
userid=0
if request.QueryString("userid")<>"" thenif isnumeric(request.QueryString("userid")) thenuserid = request.QueryString("userid") end if
end if' ---------- UPDATE CONTACT -------------
if request.form("action")="updateContact" thendim update_response, validation, validation_username, cmdFirstName, cmdLastName, cmdEmail, cmdUsername, cmdLevelvalidation=0validation_username=1cmdFirstName = request.form("firstname")cmdLastName = request.form("lastname")cmdEmail = request.form("email")cmdUsername = request.form("username")cmdLevel = request.form("userlevel")'------- validation --------------if len(cmdFirstName)<3 then validation=validation+1 end if ' first name should be at least 3 charactersif len(cmdLastName)<3 then validation=validation+1 end if ' last name should be at least 3 charactersif len(cmdEmail)<7 then validation=validation+1 end if ' email should be at least 7if instr(cmdEmail,"@")<1 then validation=validation+1 end if ' email should contain @ or use RegEXif len(cmdLevel)<3 then validation=validation+1 end if ' level should be at least 3 characters' check if username is uniqueif cmdUsername<>"" then ' allow blank usernamesSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "SELECT ID FROM dbo.ee_tUsers WHERE UserName = ? AND ID<>?" cmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 50, cmdUsername) ' adDoublecmd.Parameters.Append cmd.CreateParameter("userid", 5, 1, -1, userid) ' adDoublecmd.Prepared = trueSet rs = cmd.Executeif not rs.eof then ' the username is in use, don't updatevalidation_username=0end ifrs.Close()Set rs = Nothingend if' -------- end validation ----------if validation = 0 then ' if no errros proceedSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "UPDATE dbo.ee_tUsers SET FirstName = ?, LastName =?, Email =?, UserLevel=? WHERE ID = ?" cmd.Prepared = truecmd.Parameters.Append cmd.CreateParameter("first", 202, 1, 50, cmdFirstName) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("last", 202, 1, 50, cmdLastName) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("email", 202, 1, 150, cmdEmail) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("level", 202, 1, 50, cmdLevel) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("userid", 5, 1, -1, userid) ' adDoublecmd.Executecmd.ActiveConnection.Closeupdate_response="success|User Updated"' check if username should be updatedif validation_username=1 thenSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "UPDATE dbo.ee_tUsers SET Username = ? WHERE ID = ?" cmd.Prepared = truecmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 50, cmdUsername) ' adVarWCharcmd.Parameters.Append cmd.CreateParameter("userid", 5, 1, -1, userid) ' adDoublecmd.Executecmd.ActiveConnection.Closeelseupdate_response=update_response&"<br><div class='error'>Username in use, not updated</div>"end if' check if password should be updatedif request.form("newpassword")<>"" then 'password was submittedcmdPassword = request.form("newpassword") if validatePassword(cmdPassword)=True then ' password is validif setPassword(cmdPassword,userid) = 1 then ' run function to update password and it is goodupdate_response=update_response&"<br>Password Updated"end ifelseupdate_response=update_response&"<br><div class='error'>Password did not validate and was not updated</div>"end ifend ifelseupdate_response="error|You have "&validation&" errors.  Please set all fields"end if' resetcmdFirstName="" cmdLastName=""cmdEmail=""cmdUsername=""cmdLevel=""end if' ---------- CONTACT RECORDSET -------------
Set cmd = Server.CreateObject ("ADODB.Command")
cmd.ActiveConnection = conEE
cmd.CommandText = "SELECT ID, FirstName,LastName,Email, UserName,UserLevel FROM dbo.ee_tUsers WHERE ID = ?" 
cmd.Parameters.Append cmd.CreateParameter("userid", 5, 1, -1, userid) ' adDouble
cmd.Prepared = true
Set rs = cmd.Execute
%><%'setPassword "password",1
%>
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="UTF-8">
<title>Contact Edit</title>
</head><body>
<!--#include virtual="/ee/login/includes/nav.asp" -->
<%
if not rs.eof or not rs.bof then ' only show form if good recordset
dim arrMessage,messageClass,messageContent
' if there is a form update, show mesageif update_response<>"" then ' this is delimted by a pipe class|messagearrMessage = split(update_response,"|")messageClass = arrMessage(0)messageContent = arrMessage(1)response.write "<div class='"&messageClass&"'>"&messageContent&"</div>"'response.write messageContentend if
%>
<form method="post" action=""  autocomplete="off">
<input type="hidden" name="action" value="updateContact">
<input type="hidden" name="contactid" value="<%=rs("ID")%>">
<label>First Name</label>
<input name="firstname" value="<%=rs("FirstName")%>">
<label>Last Name</label>
<input name="lastname" value="<%=rs("LastName")%>">
<label>Email</label>
<input name="email" value="<%=rs("Email")%>">
<label>username</label>
<input name="username"  value="<%=rs("UserName")%>">
<label>User Level</label>
<select name="userlevel"><option value="">No Log In</option><option value="Admin"<%if rs("UserLevel")="Admin" then response.write " selected" end if%>>Admin</option><option value="Support"<%if rs("UserLevel")="Support" then response.write " selected" end if%>>Support</option><option value="Sales"<%if rs("UserLevel")="Sales" then response.write " selected" end if%>>Sales</option>
</select>
<p class="notice">
NOTE:<br>The current password can not be displayed.<br>
If the user forgot their password, you may set a new password by entering the password field below.
</p>
<p class="notice">Leave blank to keep current password.</p>
<label>New Password</label>
<input name="newpassword">
<button type="submit">Submit</button>
</form>
<%
elseresponse.write "ERROR: Bad User ID"
end if
%>
</body>
</html>
<%
rs.Close()
Set rs = Nothing
%> 

STYLE.CSS

样式

.nav{padding:10px;font-size:115%;border-bottom:solid;
}
#login{width:500px;margin-left:auto;margin-right:auto;
}
#login form{font-size:110%;
}
#login input{color:grey;}
.notice {font-size:85%;color:red;
}
.error {background-color:pink;
}
.success {background-color:LightGreen;
}
label{width:100px;display:block
}
input,select{display:block;margin-bottom:10px;
}
table.usertable {width:600px;
}table.usertable tr:nth-child(even) {background-color: #eee;
}
table.usertable tr:nth-child(odd) {background-color:#fff;
}
table.usertable th	{background-color: black;color: white;
} 

INCLUDES/CONFIG.ASP

包含/配置ASP

<%
option explicit 
' config and function variables
Dim conEE,secret_key,login_session_minutes,main_login_page
conEE = "Provider=SQLOLEDB; datasource=localhost; Database=db_name; Uid=username; Pwd=password"' ---- config set up ---- 
secret_key 					= "aBc123Xyz456LMNop" ' use a long random string '
login_session_minutes	= 60 ' total time per session in minutes
main_login_page 		= "/ee/login/"  'where to redirect for the main log in page%> 

INCLUDES/FUNCTIONS.ASP

包含/功能

<%
DIM strAuth,logged_in_status,logged_in_user,logged_in_level,foundToken,arrAuth
DIM passHash,zPass,zUserID,zUserName,cmdFunction,rsFunction,fnPassword,token_expires,token,logged_in_expires' to be placed at the top on every page you want secured'
logged_in_status = "0"
strAuth = lookupToken ' find token using function'
if strAuth <> "0" then ' has dataarrAuth=split(strAuth,"|") ' create an array from our pipe delimited return'logged_in_status 	= arrAuth(0)logged_in_user 		= arrAuth(1)logged_in_level 		= arrAuth(2) ' Level_1, level_2, Level_3, Admin, Author, User'logged_in_expires   = arrAuth(3)
end if' ---- Set a token to cookie and db ----'
function setToken(zUserID,zUserName)' logout any remaining tokenslogOutToken(zUserID)'set token in cookie and log in table for 1 hourtoken_expires = dateAdd("n",login_session_minutes,now)token = sha256(now&zUserName&secret_key)Response.Cookies("domaintoken")=tokenResponse.Cookies("domaintoken").Expires=cdate(token_expires)Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "INSERT INTO  ee_tLoginTrans (UserID,UserName,Token,TokenExpires,LoggedIP,LoggedTimeStamp) VALUES(?,?,?,?,?,?)"cmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 5, 1, -1, zUserID) 'int user idcmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 202, 1, 50, zUserName) 'string usernamecmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 202, 1, 350,token ) 'string tokencmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 135, 1, -1, token_expires) 'stringcmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 202, 1, 50,  Request.ServerVariables("REMOTE_ADDR")) 'stringcmdFunction.Parameters.Append cmdFunction.CreateParameter("username", 135, 1, -1, now) 'stringcmdFunction.Prepared = truecmdFunction.ExecutecmdFunction.ActiveConnection.Closeend function' ------- LOG OUT - Remove token string from login trans ---------
function logOutToken(zUserID)Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "UPDATE dbo.ee_tLoginTrans  SET Token='' WHERE UserID = ? AND Token<>''" cmdFunction.Prepared = truecmdFunction.Parameters.Append cmdFunction.CreateParameter("userid", 5, 1, -1, zUserID) ' adDoublecmdFunction.ExecutecmdFunction.ActiveConnection.Closeend function' ---- look up cookie----'
function lookupToken()
dim rsFoundTokenlookupToken="0" ' return bad 'foundToken = Request.Cookies("domaintoken")if foundToken<>"" then ' if token cookie found then look up db'Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "SELECT UserID, UserName, Token, TokenExpires, LoggedIP, LoggedTimeStamp, UserLevel FROM            ee_vLoggedInUsers WHERE Token = ?" cmdFunction.Parameters.Append cmdFunction.CreateParameter("domaintoken", 202, 1, 350, request.Cookies("domaintoken")) 'cmdFunction.Prepared = trueSet rsFoundToken= cmdFunction.ExecuteIf not rsFoundToken.bof or not rsFoundToken.eof then' pipe delimited return  username|admin'lookupToken="1|"&rsFoundToken("UserName")&"|"&rsFoundToken("UserLevel")&"|"&rsFoundToken("TokenExpires")end ifrsFoundToken.Close()Set rsFoundToken = Nothingend if
end function' ----Check Authentication ----'
' if you do not use levels, you can simply run this function at the top of every page.
function authenticate()if cstr(logged_in_status)="0" thenresponse.redirect main_login_page ' not logged in, send away'end if
end function' ---- Redirect Based On User Level ----'
function redirectLoginLevel(logged_in_level)select case logged_in_levelcase "Admin"response.Redirect("admin.asp")case "Support"response.Redirect("support.asp")case "Sales"response.Redirect("sales.asp")end selectend function' ---- Update User Password----'
function setPassword(zPass,zUserID)' get the usernamezUserName=""Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "SELECT * FROM dbo.ee_tUsers WHERE ID = ?" cmdFunction.Parameters.Append cmdFunction.CreateParameter("userid", 4, 1, -1, zUserID) 'cmdFunction.Prepared = trueSet rsFunction = cmdFunction.Executeif not rsFunction.eof thenzUserName=rsFunction("UserName")end ifrsFunction.Close()Set rsFunction = Nothing' create the password hashif zUserName<> "" thenpassHash = passwordHash(zUserName,zPass)Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "UPDATE dbo.ee_tUsers SET Password = ? WHERE ID = ?" cmdFunction.Prepared = truecmdFunction.Parameters.Append cmdFunction.CreateParameter("param1", 202, 1, 350, passHash) ' adVarWCharcmdFunction.Parameters.Append cmdFunction.CreateParameter("param2", 5, 1, -1, zUserID) ' adDoublecmdFunction.ExecutecmdFunction.ActiveConnection.ClosesetPassword = 1elsesetPassword=0end ifend functionfunction validatePassword(fnPassword)'' .aspx?k=password&c=4&m=5&ps=20' This regex can be used to restrict passwords to a length of 8 to 20 aplhanumeric characters 'and select special characters. The password also can not start with a digit, underscore or special character' and must contain at least one digit.'Matches	password1 | pa$$word2 | pa!@#$%3'Non-Matches	password | 1stpassword | $password#'Author Michael AshDim re, targetStringSet re = New RegExpWith re.Pattern = "^(?=[^\d_].*?\d)\w(\w|[!@#$%]){7,20}".Global = False.IgnoreCase = FalseEnd WithtargetString = fnPasswordvalidatePassword = re.Test(targetString)end function' ---- Hash a password ----'
function passwordHash(zUserName,zPass)passwordHash=sha256(zUserName&zPass&secret_key)
end function' ---- SHA 256 FUNCTION ----
' See the VB6 project that accompanies this sample for full code comments on how
' it works.
'
' ASP VBScript code for generating a SHA256 'digest' or 'signature' of a string. The
' MD5 algorithm is one of the industry standard methods for generating digital
' signatures. It is generically known as a digest, digital signature, one-way
' encryption, hash or checksum algorithm. A common use for SHA256 is for password
' encryption as it is one-way in nature, that does not mean that your passwords
' are not free from a dictionary attack.
'
' If you are using the routine for passwords, you can make it a little more secure
' by concatenating some known random characters to the password before you generate
' the signature and on subsequent tests, so even if a hacker knows you are using
' SHA-256 for your passwords, the random characters will make it harder to dictionary
' attack.
'
' NOTE: Due to the way in which the string is processed the routine assumes a
' single byte character set. VB passes unicode (2-byte) character strings, the
' ConvertToWordArray function uses on the first byte for each character. This
' has been done this way for ease of use, to make the routine truely portable
' you could accept a byte array instead, it would then be up to the calling
' routine to make sure that the byte array is generated from their string in
' a manner consistent with the string type.
'
' This is 'free' software with the following restrictions:
'
' You may not redistribute this code as a 'sample' or 'demo'. However, you are free
' to use the source code in your own code, but you may not claim that you created
' the sample code. It is expressly forbidden to sell or profit from this source code
' other than by the knowledge gained or the enhanced value added by your own code.
'
' Use of this software is also done so at your own risk. The code is supplied as
' is without warranty or guarantee of any kind.
'
' Should you wish to commission some derivative work based on this code provided
' here, or any consultancy work, please do not hesitate to contact us.
'
' Web Site:  
' E-mail:    sales@frez.co.ukPrivate m_lOnBits(30)
Private m_l2Power(30)
Private K(63)Private Const BITS_TO_A_BYTE = 8
Private Const BYTES_TO_A_WORD = 4
Private Const BITS_TO_A_WORD = 32m_lOnBits(0) = CLng(1)
m_lOnBits(1) = CLng(3)
m_lOnBits(2) = CLng(7)
m_lOnBits(3) = CLng(15)
m_lOnBits(4) = CLng(31)
m_lOnBits(5) = CLng(63)
m_lOnBits(6) = CLng(127)
m_lOnBits(7) = CLng(255)
m_lOnBits(8) = CLng(511)
m_lOnBits(9) = CLng(1023)
m_lOnBits(10) = CLng(2047)
m_lOnBits(11) = CLng(4095)
m_lOnBits(12) = CLng(8191)
m_lOnBits(13) = CLng(16383)
m_lOnBits(14) = CLng(32767)
m_lOnBits(15) = CLng(65535)
m_lOnBits(16) = CLng(131071)
m_lOnBits(17) = CLng(262143)
m_lOnBits(18) = CLng(524287)
m_lOnBits(19) = CLng(1048575)
m_lOnBits(20) = CLng(2097151)
m_lOnBits(21) = CLng(4194303)
m_lOnBits(22) = CLng(8388607)
m_lOnBits(23) = CLng(16777215)
m_lOnBits(24) = CLng(33554431)
m_lOnBits(25) = CLng(67108863)
m_lOnBits(26) = CLng(134217727)
m_lOnBits(27) = CLng(268435455)
m_lOnBits(28) = CLng(536870911)
m_lOnBits(29) = CLng(1073741823)
m_lOnBits(30) = CLng(2147483647)m_l2Power(0) = CLng(1)
m_l2Power(1) = CLng(2)
m_l2Power(2) = CLng(4)
m_l2Power(3) = CLng(8)
m_l2Power(4) = CLng(16)
m_l2Power(5) = CLng(32)
m_l2Power(6) = CLng(64)
m_l2Power(7) = CLng(128)
m_l2Power(8) = CLng(256)
m_l2Power(9) = CLng(512)
m_l2Power(10) = CLng(1024)
m_l2Power(11) = CLng(2048)
m_l2Power(12) = CLng(4096)
m_l2Power(13) = CLng(8192)
m_l2Power(14) = CLng(16384)
m_l2Power(15) = CLng(32768)
m_l2Power(16) = CLng(65536)
m_l2Power(17) = CLng(131072)
m_l2Power(18) = CLng(262144)
m_l2Power(19) = CLng(524288)
m_l2Power(20) = CLng(1048576)
m_l2Power(21) = CLng(2097152)
m_l2Power(22) = CLng(4194304)
m_l2Power(23) = CLng(8388608)
m_l2Power(24) = CLng(16777216)
m_l2Power(25) = CLng(33554432)
m_l2Power(26) = CLng(67108864)
m_l2Power(27) = CLng(134217728)
m_l2Power(28) = CLng(268435456)
m_l2Power(29) = CLng(536870912)
m_l2Power(30) = CLng(1073741824)K(0) = &H428A2F98
K(1) = &H71374491
K(2) = &HB5C0FBCF
K(3) = &HE9B5DBA5
K(4) = &H3956C25B
K(5) = &H59F111F1
K(6) = &H923F82A4
K(7) = &HAB1C5ED5
K(8) = &HD807AA98
K(9) = &H12835B01
K(10) = &H243185BE
K(11) = &H550C7DC3
K(12) = &H72BE5D74
K(13) = &H80DEB1FE
K(14) = &H9BDC06A7
K(15) = &HC19BF174
K(16) = &HE49B69C1
K(17) = &HEFBE4786
K(18) = &HFC19DC6
K(19) = &H240CA1CC
K(20) = &H2DE92C6F
K(21) = &H4A7484AA
K(22) = &H5CB0A9DC
K(23) = &H76F988DA
K(24) = &H983E5152
K(25) = &HA831C66D
K(26) = &HB00327C8
K(27) = &HBF597FC7
K(28) = &HC6E00BF3
K(29) = &HD5A79147
K(30) = &H6CA6351
K(31) = &H14292967
K(32) = &H27B70A85
K(33) = &H2E1B2138
K(34) = &H4D2C6DFC
K(35) = &H53380D13
K(36) = &H650A7354
K(37) = &H766A0ABB
K(38) = &H81C2C92E
K(39) = &H92722C85
K(40) = &HA2BFE8A1
K(41) = &HA81A664B
K(42) = &HC24B8B70
K(43) = &HC76C51A3
K(44) = &HD192E819
K(45) = &HD6990624
K(46) = &HF40E3585
K(47) = &H106AA070
K(48) = &H19A4C116
K(49) = &H1E376C08
K(50) = &H2748774C
K(51) = &H34B0BCB5
K(52) = &H391C0CB3
K(53) = &H4ED8AA4A
K(54) = &H5B9CCA4F
K(55) = &H682E6FF3
K(56) = &H748F82EE
K(57) = &H78A5636F
K(58) = &H84C87814
K(59) = &H8CC70208
K(60) = &H90BEFFFA
K(61) = &HA4506CEB
K(62) = &HBEF9A3F7
K(63) = &HC67178F2Private Function LShift(lValue, iShiftBits)If iShiftBits = 0 ThenLShift = lValueExit FunctionElseIf iShiftBits = 31 ThenIf lValue And 1 ThenLShift = &H80000000ElseLShift = 0End IfExit FunctionElseIf iShiftBits < 0 Or iShiftBits > 31 ThenErr.Raise 6End IfIf (lValue And m_l2Power(31 - iShiftBits)) ThenLShift = ((lValue And m_lOnBits(31 - (iShiftBits + 1))) * m_l2Power(iShiftBits)) Or &H80000000ElseLShift = ((lValue And m_lOnBits(31 - iShiftBits)) * m_l2Power(iShiftBits))End If
End FunctionPrivate Function RShift(lValue, iShiftBits)If iShiftBits = 0 ThenRShift = lValueExit FunctionElseIf iShiftBits = 31 ThenIf lValue And &H80000000 ThenRShift = 1ElseRShift = 0End IfExit FunctionElseIf iShiftBits < 0 Or iShiftBits > 31 ThenErr.Raise 6End IfRShift = (lValue And &H7FFFFFFE) \ m_l2Power(iShiftBits)If (lValue And &H80000000) ThenRShift = (RShift Or (&H40000000 \ m_l2Power(iShiftBits - 1)))End If
End FunctionPrivate Function AddUnsigned(lX, lY)Dim lX4Dim lY4Dim lX8Dim lY8Dim lResultlX8 = lX And &H80000000lY8 = lY And &H80000000lX4 = lX And &H40000000lY4 = lY And &H40000000lResult = (lX And &H3FFFFFFF) + (lY And &H3FFFFFFF)If lX4 And lY4 ThenlResult = lResult Xor &H80000000 Xor lX8 Xor lY8ElseIf lX4 Or lY4 ThenIf lResult And &H40000000 ThenlResult = lResult Xor &HC0000000 Xor lX8 Xor lY8ElselResult = lResult Xor &H40000000 Xor lX8 Xor lY8End IfElselResult = lResult Xor lX8 Xor lY8End IfAddUnsigned = lResult
End FunctionPrivate Function Ch(x, y, z)Ch = ((x And y) Xor ((Not x) And z))
End FunctionPrivate Function Maj(x, y, z)Maj = ((x And y) Xor (x And z) Xor (y And z))
End FunctionPrivate Function S(x, n)S = (RShift(x, (n And m_lOnBits(4))) Or LShift(x, (32 - (n And m_lOnBits(4)))))
End FunctionPrivate Function R(x, n)R = RShift(x, CInt(n And m_lOnBits(4)))
End FunctionPrivate Function Sigma0(x)Sigma0 = (S(x, 2) Xor S(x, 13) Xor S(x, 22))
End FunctionPrivate Function Sigma1(x)Sigma1 = (S(x, 6) Xor S(x, 11) Xor S(x, 25))
End FunctionPrivate Function Gamma0(x)Gamma0 = (S(x, 7) Xor S(x, 18) Xor R(x, 3))
End FunctionPrivate Function Gamma1(x)Gamma1 = (S(x, 17) Xor S(x, 19) Xor R(x, 10))
End FunctionPrivate Function ConvertToWordArray(sMessage)Dim lMessageLengthDim lNumberOfWordsDim lWordArray()Dim lBytePositionDim lByteCountDim lWordCountDim lByteConst MODULUS_BITS = 512Const CONGRUENT_BITS = 448lMessageLength = Len(sMessage)lNumberOfWords = (((lMessageLength + ((MODULUS_BITS - CONGRUENT_BITS) \ BITS_TO_A_BYTE)) \ (MODULUS_BITS \ BITS_TO_A_BYTE)) + 1) * (MODULUS_BITS \ BITS_TO_A_WORD)ReDim lWordArray(lNumberOfWords - 1)lBytePosition = 0lByteCount = 0Do Until lByteCount >= lMessageLengthlWordCount = lByteCount \ BYTES_TO_A_WORDlBytePosition = (3 - (lByteCount Mod BYTES_TO_A_WORD)) * BITS_TO_A_BYTElByte = AscB(Mid(sMessage, lByteCount + 1, 1))lWordArray(lWordCount) = lWordArray(lWordCount) Or LShift(lByte, lBytePosition)lByteCount = lByteCount + 1LooplWordCount = lByteCount \ BYTES_TO_A_WORDlBytePosition = (3 - (lByteCount Mod BYTES_TO_A_WORD)) * BITS_TO_A_BYTElWordArray(lWordCount) = lWordArray(lWordCount) Or LShift(&H80, lBytePosition)lWordArray(lNumberOfWords - 1) = LShift(lMessageLength, 3)lWordArray(lNumberOfWords - 2) = RShift(lMessageLength, 29)ConvertToWordArray = lWordArray
End FunctionPublic Function SHA256(sMessage)Dim HASH(7)Dim MDim W(63)Dim aDim bDim cDim dDim eDim fDim gDim hDim iDim jDim T1Dim T2HASH(0) = &H6A09E667HASH(1) = &HBB67AE85HASH(2) = &H3C6EF372HASH(3) = &HA54FF53AHASH(4) = &H510E527FHASH(5) = &H9B05688CHASH(6) = &H1F83D9ABHASH(7) = &H5BE0CD19M = ConvertToWordArray(sMessage)For i = 0 To UBound(M) Step 16a = HASH(0)b = HASH(1)c = HASH(2)d = HASH(3)e = HASH(4)f = HASH(5)g = HASH(6)h = HASH(7)For j = 0 To 63If j < 16 ThenW(j) = M(j + i)ElseW(j) = AddUnsigned(AddUnsigned(AddUnsigned(Gamma1(W(j - 2)), W(j - 7)), Gamma0(W(j - 15))), W(j - 16))End IfT1 = AddUnsigned(AddUnsigned(AddUnsigned(AddUnsigned(h, Sigma1(e)), Ch(e, f, g)), K(j)), W(j))T2 = AddUnsigned(Sigma0(a), Maj(a, b, c))h = gg = ff = ee = AddUnsigned(d, T1)d = cc = bb = aa = AddUnsigned(T1, T2)NextHASH(0) = AddUnsigned(a, HASH(0))HASH(1) = AddUnsigned(b, HASH(1))HASH(2) = AddUnsigned(c, HASH(2))HASH(3) = AddUnsigned(d, HASH(3))HASH(4) = AddUnsigned(e, HASH(4))HASH(5) = AddUnsigned(f, HASH(5))HASH(6) = AddUnsigned(g, HASH(6))HASH(7) = AddUnsigned(h, HASH(7))NextSHA256 = LCase(Right("00000000" & Hex(HASH(0)), 8) & Right("00000000" & Hex(HASH(1)), 8) & Right("00000000" & Hex(HASH(2)), 8) & Right("00000000" & Hex(HASH(3)), 8) & Right("00000000" & Hex(HASH(4)), 8) & Right("00000000" & Hex(HASH(5)), 8) & Right("00000000" & Hex(HASH(6)), 8) & Right("00000000" & Hex(HASH(7)), 8))
End Function
%> 

INCLUDES/NAV.ASP

包含/NAV.ASP

<div><%if isArray(arrAuth) then ' 'if logged inresponse.write "Welcome "&logged_in_user&" your session expires "&logged_in_expiresend if %>
</div>
<div class="nav"><a href="index.asp">Log In</a> |<a href="userAdd.asp">New User</a> |<a href="admin.asp">Admin </a> |<a href="loggedinusers.asp">Logged In Users |</a><a href="sales.asp">Sales |</a><a href="support.asp">Support |</a>
</div> 

To add yourself as the first user, you will need to do this without having to log in. At the top of the UserAdd.asp, comment out the line 8, response.Redirect("index.asp"). We need this removed to allow you on the page. For the user level, set yourself as "Admin". The password must start with a character and contain at least one digit. For regular Expression help, you can do an advanced search on Experts Exchange .jsp, click Question and select the topic Regular Expression. You can also find help at or .aspx?k=password&c=4&m=5&ps=20.

要将您自己添加为第一个用户,您将无需登录就可以执行此操作。在UserAdd.asp的顶部,注释掉第8行,response.Redirect(“ index.asp”)。 我们需要将其删除以允许您进入页面。 对于用户级别,将自己设置为“管理员”。 密码必须以字符开头,并且至少包含一位数字。 要获取正则表达式帮助,可以在Experts Exchange .jsp上进行高级搜索,单击“问题”,然后选择正则表达式主题。 您还可以在://regexlib.com/Search.aspx?k=password&c=4&m=5&ps=20上找到帮助。

Once you have created yourself as a user, add back the code on line 8,response.Redirect("index.asp"). Now you can go to your index page and log in. For this demo site, the Admin page lists all the users you have created. The LoggedInUsers.asp page shows who is logged in by using the view you created. Try creating a second user, then log in as that user on another browser. With your admin credentials, if you refresh the LoggedInUsers.asp page you can see two users. If you click the Submit button under the logout column for your second user, that user will be logged out and on the next page refresh will be sent back to main log in page. This is because we removed the token from the login transaction table. If you look at your database, you will see the row still exists, but the token field is missing.

创建用户身份后,请在第8行上添加代码,response.Redirect(“ index.asp”)。 现在,您可以转到索引页面并登录。对于此演示站点,“管理”页面列出了您创建的所有用户。 LoggedInUsers.asp页显示使用创建的视图登录的人。 尝试创建第二个用户,然后以该用户身份登录另一个浏览器。 使用管理员凭据,如果刷新LoggedInUsers.asp页,则可以看到两个用户。 如果您单击第二个用户的注销列下的“提交”按钮,则该用户将被注销,刷新将在下一页发送回主登录页面。 这是因为我们从登录事务表中删除了令牌。 如果查看数据库,将看到该行仍然存在,但是令牌字段丢失。

Because there are several user levels, I created a function that will forward users to the different page once logged in based on their user credentials.

由于存在多个用户级别,因此我创建了一个函数,该函数将根据用户的凭据将用户登录后转到其他页面。

Now for the details of how this works. Starting with the first flow chart, we have a form with a username and password. Once submitted, the username is used to look up the users table with the following SQL where the ? = the form data for the username.

现在详细了解其工作原理。 从第一个流程图开始,我们有一个带有用户名和密码的表格。 提交后,用户名将用于通过以下SQL查找users表: =用户名的表单数据。

SELECT ID, UserName,UserLevel, Password FROM dbo.ee_tUsers WHERE Username = ?  

Assuming we find the username, the next step is to match the password entered with the password stored. I have hashed the password so there is no direct way to lookup the password directly from the form data. If you look at your users table, you will see the password looks something like this: cb0ef439f1865799621cfe8beff06261642ae1902145e9e35d8adfa7c0fb99da. It is an sha256 hash using the username password and secret key as the salt. This way two people with the same password will have a different hash because the usernames are unique. There are more secure hashing algorithm's and no matter which you choose; somebody will have an opinion. Since this is classic ASP, there is a readily available source to create this hash and that is why I have chosen it. There is a good article on this subject at crackstation .htm. As an alternative to hashing with VBscript, you can also do this on SQL Server with HASHBYTES .aspx. If you go this route, you will want to create a stored procedure for these functions. This article will be talking about maintining the hashing functions in VBscript.

假设我们找到了用户名,下一步就是将输入的密码与存储的密码进行匹配。 我已经对密码进行了哈希处理,因此没有直接方法可以直接从表单数据中查找密码。 如果查看用户表,您将看到密码如下所示: cb0ef439f1865799621cfe8beff06261642ae1902145e9e35d8adfa7c0fb99da 。 它是一个sha256哈希,使用用户名密码和密钥作为盐。 这样,具有相同密码的两个人将具有不同的哈希,因为用户名是唯一的。 无论选择哪种方式,都有更安全的哈希算法。 会有人发表意见。 由于这是经典的ASP,因此有一个随时可用的源来创建此哈希,这就是我选择它的原因。 在crackstation .htm上有一篇很好的文章。 作为使用VBscript进行哈希处理的替代方法,您还可以在SQL Server上使用HASHBYTES .aspx进行此操作 。 如果走这条路线,您将要为这些功能创建一个存储过程。 本文将讨论维护VBscript中的哈希函数。

DECLARE @HashThis nvarchar(4000);
SET @HashThis = CONVERT(nvarchar(4000),'dslfdkjLK85kldhnv$n000#knf');
SELECT HASHBYTES('SHA1', @HashThis); 

Because the stored password is hashed in our database, the way to check if the password is correct is to run the submitted password through our hashing function then match the result with what is stored in the database.

因为存储的密码在我们的数据库中是散列的,所以检查密码是否正确的方法是通过我们的散列函数运行提交的密码,然后将结果与数据库中存储的内容进行匹配。

The function that does this is below. The sha256 function is the large function at the bottom of the functions.asp page. It is simply creating the hash as sha256("sometext"). For the text, we are concatenating the username, password and secret key. This is what is referred to as salting.

执行此操作的功能如下。 sha256函数是functions.asp页底部的大型函数。 它只是将哈希创建为sha256(“ sometext”)。 对于文本,我们将用户名,密码和密钥串联在一起。 这就是所谓的盐化。

' ---- Hash a password ----'
function passwordHash(zUserName,zPass)passwordHash=sha256(zUserName&zPass&secret_key)
end function 

On the index.asp code if there is a submitted form with the field username, we our look up of the user table. Then run the submitted password through the passwordHash function and match that result with the password found in the database.

在index.asp代码上,如果存在带有用户名字段的提交表单,我们将查询user表。 然后通过passwordHash函数运行提交的密码,并使结果与数据库中找到的密码匹配。

If the password is a match, we create a token which is another salted hash. This hash is set as a cookie and stored in the LoginTrans table using the field named Token.

如果密码匹配,我们将创建一个令牌,该令牌是另一个带盐的哈希。 将此哈希设置为cookie,并使用名为Token的字段存储在LoginTrans表中。

On every subsequent page load, we look up the cookie to get the token, then search for the token in the LoginTrans table. If found, test that the expiration date is good and proceed.

在随后的每次页面加载中,我们都会查询cookie以获取令牌,然后在LoginTrans表中搜索令牌。 如果找到,请测试有效期限并继续。

At the top of ever page we get the status, logged in user, their level and expires from the log in trans. The lookupToken function searches the database for the token found in the cookie then returns a pipe delimited response.

在每页的顶部,我们会获得状态,已登录的用户,其级别,并从trans的登录到期。 lookupToken函数在数据库中搜索在cookie中找到的令牌,然后返回管道分隔的响应。

logged_in_status = "0"
strAuth = lookupToken ' find token using function'
if strAuth <> "0" then ' has dataarrAuth=split(strAuth,"|") ' create an array from our pipe delimited return'logged_in_status     = arrAuth(0)logged_in_user         = arrAuth(1)logged_in_level     = arrAuth(2) ' Level_1, level_2, Level_3, Admin, Author, User'logged_in_expires   = arrAuth(3)
end if' ---- look up cookie----'
function lookupToken()
dim rsFoundTokenlookupToken="0" ' return bad 'foundToken = Request.Cookies("domaintoken")if foundToken<>"" then ' if token cookie found then look up db'Set cmdFunction = Server.CreateObject ("ADODB.Command")cmdFunction.ActiveConnection = conEEcmdFunction.CommandText = "SELECT UserID, UserName, Token, TokenExpires, LoggedIP, LoggedTimeStamp, UserLevel FROM            ee_vLoggedInUsers WHERE Token = ?" cmdFunction.Parameters.Append cmdFunction.CreateParameter("domaintoken", 202, 1, 350, request.Cookies("domaintoken")) 'cmdFunction.Prepared = trueSet rsFoundToken= cmdFunction.ExecuteIf not rsFoundToken.bof or not rsFoundToken.eof then' pipe delimited return  username|admin'lookupToken="1|"&rsFoundToken("UserName")&"|"&rsFoundToken("UserLevel")&"|"&rsFoundToken("TokenExpires")end ifrsFoundToken.Close()Set rsFoundToken = Nothingend if
end function 

It is important to have unique usernames and there is a function that helps when a username is selected. In both the Edit and Add user pages, there is a look up that makes sure the username is unique.  

拥有唯一的用户名很重要,并且有一个功能可以在选择用户名时提供帮助。 在“编辑”和“添加用户”页面中,都有一个查询来确保用户名是唯一的。

    ' check if username is uniqueif cmdUsername<>"" then ' allow blank usernamesSet cmd = Server.CreateObject ("ADODB.Command")cmd.ActiveConnection = conEEcmd.CommandText = "SELECT ID FROM dbo.ee_tUsers WHERE UserName = ?" cmd.Parameters.Append cmd.CreateParameter("username", 202, 1, 50, cmdUsername)cmd.Prepared = trueSet rs = cmd.Executeif not rs.eof then ' the username is in use, don't updatevalidation_username=0end ifrs.Close()Set rs = Nothingend if 

For the page authentication, at the top of every page you will see code below. What is happening is the functions.asp page is loading and retrieving the cookie with the token and doing the look up of the user and placing the data into several fields. One field is status and another is user level. In the code directly below we are looking to see if the status is "0" or if the words, "Admin" or "Support" are not found. If that is the case, we redirect them to the index page. If you have multiple user levels that are allowed on the page, just add more seperated by a space.  

对于页面身份验证,在每个页面的顶部,您将在下面看到代码。 发生的是functions.asp页正在加载和检索带有令牌的cookie,并进行用户查找并将数据放入几个字段中。 一个字段是状态,另一个字段是用户级别。 在下面的代码中,我们正在查看状态是否为“ 0”,或者是否未找到“ Admin”或“ Support”一词。 如果是这种情况,我们会将其重定向到索引页面。 如果页面上允许有多个用户级别,则只需添加多个以空格分隔的用户即可。

if logged_in_status = "0" OR  instr("Support Admin",logged_in_level)<1 thenresponse.Redirect("index.asp")
end if 

If you allow multiple user levels on one page and want to restrict a specific portion of one page to only one user level, you can use the sample code in the support.asp page. Here we are using the variable logged_in_level and testing if it is set to "Admin". If it is, then show the html inside the if/then.

如果在一页上允许多个用户级别,并且要将页面的特定部分限制为仅一个用户级别,则可以使用support.asp页中的示例代码。 在这里,我们使用变量logging_in_level并测试它是否设置为“ Admin”。 如果是,则在if / then内显示html。

<h1>Support</h1>
<div>This section can be seen by Support and Admin</div>
<%
if logged_in_level = "Admin" then
%>
<div>This section can be seen ONLY by Admin</div>
<%
end if
%> 

If your page will only have one user level, you can use the code below instead. 

如果您的页面只有一个用户级别,则可以改用下面的代码。

if logged_in_status = "0" OR logged_in_level<>"Admin" thenresponse.Redirect("index.asp")
end if 

Because we are adding a row of data to the login trans table, you could develop a report that shows all past logins, how many times any one user logged in, how many times all users logged in between two dates or there are APIs you can use to lookup an IP and get its location.

由于我们正在向登录转换表中添加一行数据,因此您可以开发一个报告,以显示所有过去的登录信息,一个用户登录的次数,两个日期之间所有用户登录的次数或可以使用的API用于查找IP并获取其位置。

Another option you may want to impliment for your users is showing the amount of time they have left until their session expires. A simple way is to simply display the logged_in_expires field.

您可能要隐含给用户的另一种选择是显示他们的会话期满之前所剩下的时间。 一种简单的方法是仅显示logging_in_expires字段。

response.write logged_in_expires 

This will show the full date and time staticly. If you would like to show some type of countdown timer, I would suggest creating an animated countdown timer in javascript or use a ready made project. For the start time, you can use the field logged_in_expires.

这将静态显示完整的日期和时间。 如果您想显示某种倒数计时器,建议您在javascript中创建一个动画的倒数计时器或使用现成的项目。 对于开始时间,您可以使用字段logging_in_expires。

You choose an animated countdown timer such as .countdown/. They show a code sample:

您可以选择一个动画的倒数计时器,例如.countdown/ 。 他们显示了一个代码示例:

<div id="getting-started"></div><script type="text/javascript">$("#getting-started").countdown("2016/01/01", function(event) {$(this).text(event.strftime('%D days %H:%M:%S'));});</script> 

The modification you would need to make could be:

您需要进行的修改可能是:

<div id="getting-started"></div><script type="text/javascript">
<%
dim countdown_time
countdown_time=year(logged_in_expires)&"/"& right("0"&month(logged_in_expires),2)&"/"&right("0"&day(logged_in_expires),2)
%>$("#getting-started").countdown("<%=countdown_time%>", function(event) {$(this).text(event.strftime('%D days %H:%M:%S'));});</script> 

On the config.asp page, we are setting the default log in time for 60 minutes. Feel free to change that to whatever number you want. If you prefer to allow people to be logged in for a specific number of days, weeks or months instead of  minutes, you can either do the conversion to minutes yourself, or find the line of code in the functions.asp page that sets the token_expires variable. The letter "n" signifies minutes. If you want to use days, use a "d" or "m" for months. .asp   

在config.asp页上,我们将默认登录时间设置为60分钟。 随意将其更改为您想要的任何数字。 如果您希望允许人们登录特定天数,数周或数月而不是数分钟,则可以自己转换为分钟数,也可以在functions.asp页面中找到设置token_expires的代码行变量。 字母“ n”表示分钟。 如果要使用几天,请使用“ d”或“ m”数月。 .asp

token_expires = dateAdd("n",login_session_minutes,now) 

You will also see a secret_key variable on the config.asp page. Make sure to change this to something else. It can be any combination of characters you want. Just make sure it is random and long.

您还将在config.asp页面上看到secret_key变量。 确保将其更改为其他内容。 它可以是您想要的字符的任意组合。 只要确保它是随机且长的即可。

翻译自: .html

令牌桶生成令牌

本文标签: 令牌桶生成令牌