?? username-password database for tclhttpd.mht
字號:
From: =?gb2312?B?08kgV2luZG93cyBJbnRlcm5ldCBFeHBsb3JlciA3ILGjtOY=?=
Subject: Username/Password Database for Tclhttpd
Date: Fri, 29 Feb 2008 00:32:55 +0800
MIME-Version: 1.0
Content-Type: multipart/related;
type="text/html";
boundary="----=_NextPart_000_0081_01C87A6A.A0310BB0"
X-MimeOLE: Produced By Microsoft MimeOLE V6.0.6000.16545
這是 MIME 格式的多方郵件。
------=_NextPart_000_0081_01C87A6A.A0310BB0
Content-Type: text/html;
charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Location: http://wiki.tcl.tk/8657
=EF=BB=BF<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" =
"http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<HTML lang=3Den><HEAD><TITLE>Username/Password Database for =
Tclhttpd</TITLE>
<META http-equiv=3DContent-Type content=3D"text/html; charset=3Dutf-8">
<STYLE type=3Dtext/css media=3Dall>@import url( /wikit.css );
</STYLE>
<LINK title=3DRSS href=3D"/rss.xml" type=3Dapplication/rss+xml =
rel=3Dalternate><!--[if lte IE 6]>=0A=
<style type=3D'text/css' media=3D'all'>@import 'ie6.css';</style>=0A=
<![endif]--><!--[if gte IE 7]>
<STYLE type=3Dtext/css media=3Dall>@import url( ie7.css );
</STYLE>
<![endif]-->
<SCRIPT type=3Dtext/javascript>=0A=
function init() {=0A=
// quit if this function has already been called=0A=
if (arguments.callee.done) return;=0A=
=0A=
// flag this function so we don't do the same thing twice=0A=
arguments.callee.done =3D true;=0A=
=0A=
try {=0A=
checkTOC();=0A=
} catch (err) {=0A=
/* nothing */=0A=
}=0A=
};=0A=
=0A=
/* for Mozilla */=0A=
if (document.addEventListener) {=0A=
document.addEventListener("DOMContentLoaded", init, false);=0A=
}=0A=
=0A=
/* for Internet Explorer */=0A=
/*@cc_on @*/=0A=
/*@if (@_win32)=0A=
document.write("<script defer src=3Die_onload.js><\/script>");=0A=
/*@end @*/=0A=
=0A=
/* for other browsers */=0A=
window.onload =3D init;=0A=
</SCRIPT>
<META content=3D"MSHTML 6.00.6000.16609" name=3DGENERATOR></HEAD>
<BODY>
<DIV class=3Dcontainer>
<DIV class=3Dheader>
<DIV class=3Dlogo><A class=3Dlogo =
href=3D"http://wiki.tcl.tk/">wiki.tcl.tk</A> </DIV>
<DIV class=3Dtitle id=3Dtitle><A title=3D"click to see 2 references to =
this page"=20
href=3D"http://wiki.tcl.tk/_ref/8657">Username/Password Database for=20
Tclhttpd</A></DIV>
<DIV class=3Dupdated id=3Dupdated>Updated 2005-06-15 14:21:22 <A =
class=3Ddelta=20
href=3D"http://wiki.tcl.tk/_diff/8657#diff0">=E2=96=B2</A></DIV></DIV>
<DIV id=3Dwrapper>
<DIV id=3Dcontent>
<P>The following example shows a username/password database for <A=20
href=3D"http://wiki.tcl.tk/2085">Tclhttpd</A>. It uses the following</P>
<UL>
<LI>Metakit for the database=20
<LI>logic and code from the <A =
href=3D"http://wiki.tcl.tk/6137">formkit</A>=20
package=20
<LI><A href=3D"http://wiki.tcl.tk/1070">crypt in pure tcl</A> from the =
wiki for=20
the passwords=20
<LI>The Tclhttpd session module for row(record) locking and session=20
control.</LI></UL>
<P><B>***</B> 10 July 2003 <A href=3D"http://wiki.tcl.tk/6132">Jeff =
Smith</A> <I>A=20
<A href=3D"http://wiki.tcl.tk/3661">Starkit</A> with a few extra =
features can be=20
found at</I> [<A href=3D"http://www.freewebs.com/headsup/userpassdb.htm" =
rel=3Dnofollow>1</A>] <B>***</B></P>
<P>Create a "dbdata" directory under the Doc_Root directory (usually=20
htdocs).</P>
<P><B>The following files are all saved to the custom directory in=20
Tclhttpd.</B></P>
<P>Get the <A href=3D"http://wiki.tcl.tk/1070">crypt in pure tcl</A> =
package and=20
save it to tclcrypt.tcl Change the proc name from crypt to tclcrypt. =
This is to=20
avoid name conflicts as Tclhttpd looks for the unix crypt.</P>
<P>Edit the first line and change it from</P><PRE> proc crypt {password =
salt} {</PRE>
<P>to</P><PRE> proc tclcrypt {password salt} {</PRE>
<P>Save the following</P>
<H4>******** Begin fmkt.tcl =
********************************************</H4><PRE> # This an example =
of a username/password database for the Tclhttpd webserver.
# It uses Metakit for the database and uses ideas from formkit for
# row or record locking. It uses the session module from Tclhttpd for =
session
# control and crypt in pure tclfrom the wiki.
# Set up the Database
mk::file open users [Doc_Root]/dbdata/users.dat
mk::view layout users.details {user longname location phone email pass =
}
# Register Document type handler.
Mtype_Add .fmkt application/x-tcl-fmkt
# Set the start page that is used to launch a new session.
set Fmkt(startpage) /start.tml
# Set the time in seconds that a session will last for.
set Fmkt(age) 300
proc Doc_application/x-tcl-fmkt {path suffix sock} {
upvar #0 Httpd$sock data
global Fmkt
append data(query) ""
set queryList [Url_DecodeQuery $data(query)]
# Destroy any old session that are laying around. In this instance
# 5 minutes is the setting.
Session_Reap $Fmkt(age) Fmkt
# Find the current session (or start a new one if session=3Dnew).
set session [Session_Match $queryList Fmkt error]
if {$session =3D=3D {}} {
Fmkt_ErrorPage $sock "The session no longer exists! $error"
return
}
# Process the query data from the previous page.
if [catch {FmktProcess $session $queryList} result] {
Httpd_ReturnData $sock text/html $result
return
}
# Expand the page in the correct session interpreter, or treat
# the page as ordinary html if the session has ended.
switch -exact -- $result {
0 { Httpd_ReturnFile $sock text/html $path }
1 { Doc_Subst $sock $path interp$session }
2 { Fmkt_ErrorPage $sock "This record locked by another user!" =
}
3 { Fmkt_ErrorPage $sock "Must enter a character!" }
4 { Fmkt_ErrorPage $sock "Record has been saved!" }
}
}
# The purpose of this procedure is to process the form query data.
# Based on the query data certain procedures are triggered.
# Parameters
# session: the session id
# query: a list of names and values produced by Url_DecodeQuery
proc FmktProcess {session query} {
global Fmkt
upvar #0 Session:$session state
set interp $state(interp)
# Process each query item.
# Some items, such as "session" and "user" are treated
# specially.
# Upon completion, zero or more of the following may occur:
# Variables and values are set in the appropriate slave
# interpreter.
# The user is defined in the state array.
# The session is destroyed.
foreach {name value} $query {
if {[string match "user" $name]} {
set user [string trim $value]
if {[string match $user ""]} {
Session_Destroy $session
return 3
} elseif {![info exist state(user)]} {
if {[Fmkt_UserLock $user]} {
Session_Destroy $session
return 2
} else {
set state(user) $user
interp eval $interp [list set user $user]
}
}
} elseif {[string match "cancel" $name] && $value} {
Session_Destroy $session
return 0
} elseif {[string match "save" $name] && $value} {
if {[Fmkt_DbSave $session $query]} {
Session_Destroy $session
return 4
} else {
return 1
}
} else {
# Define variables in the slave interpreter so they are =
there before
# we do a Doc_Subst on the page!
interp eval $interp [list set $name $value]
}
}
return 1
}
proc Fmkt_ErrorPage {sock error} {
global Fmkt
upvar #0 Httpd$sock data
append result "<META HTTP-EQUIV=3D\"REFRESH\" =
CONTENT=3D\"3;URL=3D$Fmkt(startpage)\">"
append result $error<BR><P>
append result " This page will redirect to the <A =
HREF=3D$Fmkt(startpage)>start page</A>"
Httpd_ReturnData $sock text/html $result
}
# Set the Formkit tag and view for the open datafile.
proc Fmkt_DbView {session db view} {
upvar #0 Session:$session state
set state(db) $db
set state(view) $view
return ""
}
# Check that the row or record is not being edited
# by another session.
proc Fmkt_UserLock {user} {
foreach id [info globals Session:*] {
upvar #0 $id session
if {[info exist session(user)]} {
if {[string match $session(user) $user]} {
return 1
}
}
}
return 0
}
# Retrieve row based on unique "user" and drop values
# in the session's slave interpreter
proc Fmkt_DbLookup {session} {
upvar #0 Session:$session state
set interp $state(interp)
if {[info exists state(errorpass)]} {
return
} else {
set position [mk::select $state(db).$state(view) -exact user =
$state(user)]
if {[string match "" $position]} {
foreach name [mk::view info $state(db).$state(view)] {
if {[string match "user" $name]} {
continue
} else {
interp eval $interp [list set $name ""]
}
}
} else {
set state(pass) [mk::get $state(db).$state(view)!$position =
pass]
foreach {name value} [mk::get =
$state(db).$state(view)!$position] {
interp eval $interp [list set $name $value]
}
}
unset position
interp eval $interp [list set newpass ""]
interp eval $interp [list set vfypass ""]
}
}
# Collect all the return values and check if password and verify =
password
# match. Crypt the password then write the values back to the database.
proc Fmkt_DbSave {session query} {
upvar #0 Session:$session state
set interp $state(interp)
lappend field_values user $state(user)
foreach {name value} $query {
if {[string match "session" $name]} {
continue
} elseif {[string match "save" $name]} {
continue
} elseif {[string match "newpass" $name]} {
set $name $value
interp eval $interp [list set $name $value]
} elseif {[string match "vfypass" $name]} {
set $name $value
interp eval $interp [list set $name $value]
} else {
set $name $value
lappend field_values $name $value
interp eval $interp [list set $name $value]
}
}
set newpass [string trim $newpass]
set vfypass [string trim $vfypass]
if {![info exists state(pass)]} {
if {[string match $newpass ""]} {
set state(errorpass) "Must enter a password!"
return 0
}
}
if {[string compare $newpass $vfypass] !=3D 0} {
set state(errorpass) "New and Verify Passwords do not match!"
return 0
}
set position [mk::select $state(db).$state(view) -exact user =
$state(user)]
lappend field_values pass [Fmkt_passCrypt $newpass]
if {[string match "" $position]} {
eval mk::row append $state(db).$state(view) $field_values
} else {
eval mk::set $state(db).$state(view)!$position $field_values
}
mk::file commit $state(db)
unset field_values
return 1
}
proc Fmkt_passCrypt {newpass} {
set passcrypt [tclcrypt $newpass 91]
return $passcrypt
}
proc Fmkt_formSession {session args} {
upvar #0 Session:$session state
append result "<input type=3Dhidden name=3Dsession =
value=3D\"$session\">"
return $result
}
proc Fmkt_errorPass {session} {
upvar #0 Session:$session state
if {[info exists state(errorpass)]} {
return $state(errorpass)
} else {
return
}
}
# Use this procedure for authentication. It is to be called from
# a .tclaccess file in the Directory you want authenticated access too.
# In the .tclaccess file put the following
# set realm "TclHttpd"
# set callback Fmkt_AuthChecker
proc Fmkt_AuthChecker {sock realm user pass} {
set row [mk::select users.details -exact user $user]
array set userdb [mk::get users.details!$row]
set salt [string range $userdb(pass) 0 1]
set passcrypt [tclcrypt $pass $salt]
if {[string compare $user $userdb(user)] =3D=3D 0 &&
[string compare $passcrypt $userdb(pass)] =3D=3D 0} {
return 1
} else {
return 0
}
}</PRE>
<H4>**************************** End fmkt.tcl =
**************************</H4>
<P><B>The following are placed in the /htdocs directory</B></P>
<H4>******** Begin start.tml ************</H4><PRE> [
Doc_Dynamic
]
<!Doctype HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<Html>
<Head>
<Title>Start.tml</Title>
</Head>
<Body>
<p>
This an example of a username/password database..
<p>
<a HREF=3D"page1.fmkt?session=3Dnew">Start Session</a>
</Body>
</Html></PRE>
<H4>************** End start.tml **************</H4>
<H4>**************Begin page1.fmkt ************</H4><PRE> [
DbView users details
]
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; =
charset=3Dwindows-1252">
<title>Page1.fmkt</title>
</head>
<body>
<H3>Add or Edit a User</H3>
<form method=3D"POST" action=3D"page2.fmkt">
[formSession]
<p><input type=3D"submit" value=3D"Add/Edit a Username" =
><input type=3D"text" name=3D"user" size=3D"25"></p>
</form>
<form method=3D"POST" action=3D"page1.fmkt">
<p>
<input type=3D"submit" value=3D"Cancel"><input type=3D"hidden" =
name=3D"cancel">
</form>
</body>
</html></PRE>
<H4>************ End page1.fmkt **************</H4>
<H4>************ Begin page2.fmkt ************</H4><PRE> <html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; =
charset=3Dwindows-1252">
<title>Page2.fmkt</title>
</head>
<body>
<form method=3D"POST" action=3D"page2.fmkt">
[formSession]
[DbLookup]
<input type=3Dhidden name=3Dsave value=3D1>
<TABLE width=3D\"600\" bgcolor=3D\"#cc3300\" border=3D\"1\" =
cellpadding=3D\"3\" cellspacing=3D\"3\">
<TR>
<TD>Username:</TD><TD>$user</TD>
</TR><TR>
<TD>Name:</TD><TD><INPUT type=3D\"TEXT\" =
size=3D\"25\" name=3D\"longname\" value=3D\"$longname\"></TD>
</TR><TR>
<TD>Location:</TD><TD><INPUT type=3D\"TEXT\" =
size=3D\"25\" name=3D\"location\" value=3D\"$location\"></TD>
</TR><TR>
<TD>Phone:</TD><TD><INPUT type=3D\"TEXT\" =
size=3D\"25\" name=3D\"phone\" value=3D\"$phone\"></TD>
</TR><TR>
<TD>Email:</TD><TD><INPUT type=3D\"TEXT\" =
size=3D\"25\" name=3D\"email\" value=3D\"$email\"></TD>
</TR><TR>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -