身份验证
Treefrog提供了一个简单的身份验证机制.
要实现验证功能, 你先需要创建一个模型(model)类表示用户. 这里, 我们将尝试创建一个包含* username和password*属性的用户类.
我们按下面这样定义一个表:
> CREATE TABLE user ( username VARCHAR(128) PRIMARY KEY, password VARCHAR(128) );
然后进入应用程序的根目录, 使用生成器命令创建模型(model)类.
$ tspawn usermodel user
created models/sqlobjects/userobject.h
created models/user.h
created models/user.cpp
created models/models.pro
通过指定’ usermodel’选项(或者使用’u’选项), 继承自TAbstractUser类的用户模型类将被创建.
用户模型(model)类的用户名和密码字段名默认是’username’和’password’, 当然, 你可以更改它们. 例如, 如果想使用字段名’user_id’和’pass’定义表结构, 使用生成器命令如下:
$ tspawn usermodel user user_id pass
- 你仅需要简单的将这些字段名加在命令后面即可.
不像其他普通类模型, 下面的authentication方法被增加到用户模型类中. 这个方法用来身份验证用户的名字. 出于这个目的, 用户名被设置成关键字来获取用户数据对象. 然后身份验证方法读取用户对象, 比较密码, 只有匹配才返回正确的模型对象.
User User::authenticate(const QString &username, const QString &password)
{
if (username.isEmpty() || password.isEmpty())
return User();
TSqlORMapper<UserObject> mapper;
UserObject obj = mapper.findFirst(TCriteria(UserObject::Username, username));
if (obj.isNull() || obj.password != password) {
obj.clear();
}
return User(obj);
}
请确保任何修改是基于以上的代码.
可能有身份验证处理用于外部系统. 也有可能是密码需要用md5保存.
登录
让我们创建一个控制器(controller)执行login/logout处理. 此例中, 我们将创建一个AccountController类, 有三个操作(action): form, login, 和logout.
下面的代码展示了如何实现:
> tspawn controller account form login logout
created controllers/accountcontroller.h
created controllers/accountcontroller.cpp
created controllers/controllers.pro
结果是, 一个代码骨架被生成.
在form操作(action)中, 我们能显示登录的表单.
void AccountController::form()
{
userLogout(); // 强制退出
render(); // 显示表单视图
}
在此例中, 我们简单的显示了一个表单, 但如果你已经登录了, 可能/需要重定向到一个不同的界面. 响应可以按照你的需求进行定制. 现在我们将创建一个登录表单的视图, 使用视图文件views/account/form.erb. 这里, login操作(action)放置在表单中, 用来post.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
</head>
<body>
<h1>Login Form</h1>
<div style="color: red;"><%==$message %></div>
<%== formTag(urla("login")); %>
<div>
User Name: <input type="text" name="username" value="" />
</div>
<div>
Password: <input type="password" name="password" value="" />
</div>
<div>
<input type="submit" value="Login" />
</div>
</form>
</body>
</html>
在login操作(action)中, 你可以写身份验证处理, 这个身份验证处理在用户名和密码提交后执行. 一旦身份验证成功, 调用usrLogin()方法, 然后让用户登录到系统中.
void AccountController::login()
{
QString username = httpRequest().formItemValue("username");
QString password = httpRequest().formItemValue("password");
User user = User::authenticate(username, password);
if (!user.isNull()) {
userLogin(&user);
redirect(QUrl(...));
} else {
QString message = "Login failed";
texport(message);
render("form");
}
}
- 如果没有包含user.h文件将会产生编译错误.
这样就完成了登录处理.
虽然没有包含在上面的代码中, 用户登录后建议调用userLogin()方法一次来检查重复的登录. 检查返回值(bool).
在调用userLogin()方法后, 用户模型的indentitykey()方法的返回值, 保存在会话中.同时, 用户名也被保存.
QString identityKey() const { return username(); }
你可以修改返回值, 返回值应该在系统中是唯一的. 例如, 你可以返回主键或者ID, 然后通过调用indentityKeyOfLoginUser()方法获得值.
退出
要退出, 需要做的就是简单的在操作(action)中调用userLogout()方法.
void AccountController::logout()
{
userLogout();
redirect(url("Account", "form")); // 重定向到登录表单
}
检查登录
如果像防止没有登录的用户访问, 你可以重新控制器的preFilter()方法.在那里写处理过程.
bool HogeController::preFilter()
{
if (!isUserLoggedIn()) {
redirect( ... );
return false;
}
return true;
}
当preFilter()方法返回false, 操作(action)不会在它后面执行.
如果你想在许多个控制器(controller)上限制访问, 可以将代码写在ApplicationController类的preFilter().
获取已登录用户
首先, 我们需要获取一个已登录用户的实例. 可以使用identityKeyOfLoginUser()方法获得已登录用户的识别信息. 如果返回值是空的, 表示没有会话中用户没有登录, 否则这个值是默认字符类型的用户名.
接下来, 在返回关键字的用户模型类定义一个getter方法.
User User::getByIdentityKey(const QString &username)
{
TSqlORMapper<UserObject> mapper;
TCriteria cri(UserObject::Username, username);
return User(mapper.findFirst(cri));
}
在控制器中, 使用下面的代码:
QString username = identityKeyOfLoginUser();
User loginUser = User::getByIdentityKey(username);
额外注释
在这一章中, 写的登录实现都是使用会话. 因此, 会话的生命周期和登录的生命周期是相同的.