基于前一章节环境搭建的基础上,goahead用户登录操作流程。
在web资源目录下创建一个用户登录的HTML文件,login.html文件代码内容如下
<html>
<head><title>login.html</title></head>
<body>
<h1>USER LOGIN</h1>
<form method="post" action="/action/login">
Username <input type="text" name="username" value=''><br/>
Password <input type="password" name="password" value=''><br/>
<input type="submit" name="submit" value="OK">
</form>
</body>
</html>
form表单通过post方法想/action/login提交用户名和密码。启动goahead,web服务器。在浏览器中通过http://localhost/login.html进行访问。 会出现如下界面:
goahead有两种方式读取密码的方式,一种是从文件中读取,也就是前面我们说的auth.txt中,另一种是从参数中。在websOpenAuth中,verifyPassword通过ME_GOAHEAD_AUTH_STORE宏定义来赋值,当是“file”的时候,密码校验从文件中读取websVerifyPasswordFromFile,当“pam”的时候,密码校验从参数中获取websVerifyPasswordFromPam。在头文件me.h中ME_GOAHEAD_AUTH_STORE 默认为file。
因此我们需要在auth.txt中写入一个用户名和对应的密码以及用户的角色。用户名是通过源码编译的路径下的一个gopass工具生成,gopass工具在编译后build/linux-x64-default/bin/路径下,源码在src/utils/gopass.c中。
gopass的用法gopass [--cipher cipher] [--file path] [--password password] realm user roles,如果没有修改源码这realm目前默认为example.com,接下来我们用gopass创建一个用户名是xiaoming密码是123456789的账户,roles先设置为manger。
./gopass --cipher md5 --file auth.txt --password 123456789 example.com xiaoming manger
然后cat 当前目录下auth.txt可以看到如下,说明我们在auth.txt中写入了一个用户名成功。
#
# auth.txt - Authorization data
#
user name=xiaoming password=26bcb2333915d776a6ac6bbd54f2d2a3 roles=manger
然后将auth.txt 内容拷贝到我们新建目录web_cfg目录下。接下来我们验证密码的正确性。首先需要了解,代码中已经在auth.c中函数PUBLIC int websOpenAuth(int minimal)中定义了login的action的响应处理,websDefineAction("login", loginServiceProc); loginServiceProc函数中websGetVar(wp, "username", "")获取用户名,这个username必须要与html文件中的name保持一致,websGetVar(wp, "password", "") 获取用户密码,同样password需要与html文件中的password的name属性保持一致。websLoginUser函数通过wp->route->verify对密码进行校验。
verify也就是前面描述的websVerifyPasswordFromFile函数。
PUBLIC bool websLoginUser(Webs *wp, cchar *username, cchar *password)
{
assert(wp);
assert(wp->route);
assert(username);
assert(password);
if (!wp->route || !wp->route->verify) {
return 0;
}
wfree(wp->username);
wp->username = sclone(username);
wfree(wp->password);
wp->password = sclone(password);
if (!(wp->route->verify)(wp)) {
trace(2, "Password does not match");
return 0;
}
trace(2, "Login successful for %s", username);
websCreateSession(wp);
websSetSessionVar(wp, WEBS_SESSION_USERNAME, wp->username);
return 1;
}
修改route.txt文件,用以配置一些属性,其中handler设置为action
route uri=/action/login handler=action redirect=200@/ redirect=401@/login.html
route uri=/
通过web界面输入用户名:xiaoming 用户密码:123456789点击ok后,form表单将用户名和密码提交到action/login.html中
用户添加 删除 修改密码
在goahead中,通过加载auth.txt,将用户名和密码加载到hash表中,具体流程是通过websLoad(auth),这里的auth指的是auth.txt的路径。在websLoad中通过解析auth.txt文件内容然后将用户名 密码以及角色添加在hash表中。
PUBLIC int websLoad(cchar *path)
{
..........
else if (smatch(kind, "user")) {
char *name, *password, *roles;
name = password = roles = 0;
while ((option = stok(NULL, " \t\r\n", &next)) != 0) {
key = stok(option, "=", &value);
if (smatch(key, "name")) {
name = value; //用户名
} else if (smatch(key, "password")) {
password = value; //密码
} else if (smatch(key, "roles")) {
roles = value; //roles
} else {
error("Bad user keyword %s", key);
continue;
}
}
if (websAddUser(name, password, roles) == 0) { //添加到hash表中
rc = -1;
break;
}
}
...........
}
因此在auth.c中用户的操作可以通过一下函数来实现。
1、用户添加
WebsUser *websAddUser(cchar *username, cchar *password, cchar *roles)
{
WebsUser *user;
if (!username) {
error("User is missing name");
return 0;
}
if (websLookupUser(username)) {
error("User %s already exists", username);
/* Already exists */
return 0;
}
if ((user = createUser(username, password, roles)) == 0) {
return 0;
}
if (hashEnter(users, username, valueSymbol(user), 0) == 0) {
return 0;
}
return user;
}
2、用户删除
PUBLIC int websRemoveUser(cchar *username)
{
WebsKey *key;
assert(username);
if ((key = hashLookup(users, username)) != 0) {
freeUser(key->content.value.symbol);
}
return hashDelete(users, username);
}
static void freeUser(WebsUser *up)
{
assert(up);
hashFree(up->abilities);
wfree(up->name);
wfree(up->password);
wfree(up->roles);
wfree(up);
}
3、修改密码
PUBLIC int websSetUserPassword(cchar *username, cchar *password)
{
WebsUser *user;
assert(username);
if ((user = websLookupUser(username)) == 0) {
return -1;
}
wfree(user->password);
user->password = sclone(password);
return 0;
}
4、查找用户
WebsUser *websLookupUser(cchar *username)
{
WebsKey *key;
assert(username);
if ((key = hashLookup(users, username)) == 0) {
return 0;
}
return (WebsUser*) key->content.value.symbol;
}
5、设置用户角色
PUBLIC int websSetUserRoles(cchar *username, cchar *roles)
{
WebsUser *user;
assert(username);
if ((user = websLookupUser(username)) == 0) {
return -1;
}
wfree(user->roles);
user->roles = sclone(roles);
computeUserAbilities(user);
return 0;
}