来玩Play框架06 用户验证
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!
用户验证(User Authentification)复合的使用Play框架的数个功能,包括前面已经了解的表单和数据库,以及这篇文章里要提到的加密和会话。根据应用或站点的复杂程度,用户验证也可以随之变化。这里将介绍用户验证的一个基本实现方式。
加密
为了信息安全,用户密码需要加密,而不是保存为明文。Bcrypt算法可以对明文密码进行哈希(Hash)转换。我保存在数据库中的密码,是经过转换后的文本。
JBcrypt是一个外部的包,提供了Bcrypt功能。要在build.sbt中说明这个包的来源和版本:
name := "test" version := "1.0-SNAPSHOT" libraryDependencies ++= Seq(
javaJdbc,
javaEbean,
cache,
"mysql" % "mysql-connector-java" % "5.1.18",
"org.mindrot" % "jbcrypt" % "0.3m"
) play.Project.playJavaSettings
即上面新增的jbcrypt行。重新运行Play后即可使用。为了Eclipse能自动补齐该包的相关调用,可以使用play eclipse,并重新在Eclipse引入项目。
我下面用一个小例子,来说明该Bcrypt的哈希转换。在Play中增加动作:
public static Result bcrypt() {
String passwordHash = BCrypt.hashpw("Hello",BCrypt.gensalt());
boolean correct = BCrypt.checkpw("Hello", passwordHash);
boolean wrong = BCrypt.checkpw("World", passwordHash);
return ok(passwordHash + " " + correct + " " + wrong);
}
上面程序需引入org.mindrot.jbcrypt.BCrypt。动作中对"Hello"字符串进行了哈希转换,并验证"Hello"和"World"是否为原始的明文文本。
在routes增加对应URL,/bcrypt
GET /bcrypt controllers.Application.bcrypt()
访问页面:

用户注册
有了表单、数据库和加密的基础,用户注册很容易实现。首先建立数据模型app/models/User.java:
package models; import javax.persistence.*;
import play.db.ebean.Model;
import org.mindrot.jbcrypt.BCrypt; @Entity
public class User extends Model {
@Id
private String email;
private String password; // Constructor
public User(String email, String password) {
String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt());
this.email = email;
this.password = passwordHash;
}
}
这段代码创建了User类,包含两个属性email和password。在构造器中,我对密码进行了哈希转换。
下面修改控制器Application(app/controllers/Application.java)。控制器中包含两个动作和一个表单类Registration。一个动作register()用于显示注册页面,另一个动作postRegister处理表单提交的信息,并增加相应的数据库记录。Registration则对应注册页面所显示的表格:
package controllers; import play.*;
import play.mvc.*;
import play.data.Form;
import play.data.validation.Constraints.*;import models.User; public class Application extends Controller {
public static class Registration {
public String email;
@Required
public String password;
} public static Result register() {
Form<Registration> userForm = Form.form(Registration.class);
return ok(views.html.register.render(userForm));
} public static Result postRegister() {
Form<Registration> userForm =
Form.form(Registration.class).bindFromRequest();
User user = new User(userForm.get().email, userForm.get().password);
user.save();
return ok("registered");
}
}
register()动作使用的模板为app/views/register.scala.html:
@(userForm: Form[controllers.Application.Registration]) <!DOCTYPE html>
<html>
<body>
<h1> Registration </h1>
@helper.form(action = routes.Application.postRegister()) {
@helper.inputText(userForm("email"))
@helper.inputPassword(userForm("password"))
<input type="submit">
}
</body>
</html>
在routes中为两个动作增加对应的URL:
GET /register controllers.Application.register()
POST /register controllers.Application.postRegister()
访问页面:

输入用户名和密码,可以看到数据库中增加的记录:

用户验证
将用户验证的主要逻辑放入到模型User中。修改User类,为User类增加authenticate()方法:
package models; import javax.persistence.*;
import play.db.ebean.Model;
import org.mindrot.jbcrypt.BCrypt; @Entity
public class User extends Model {
@Id
private String email;
private String password; // Constructor
public User(String email, String password) {
String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt());
this.email = email;
this.password = passwordHash;
} // Query
public static Model.Finder<Integer, User> find =
new Model.Finder<>(Integer.class, User.class); // Authentification
public static User authenticate(String email, String password) {
User user = find.where()
.eq("email", email)
.findUnique();
if (user == null) {
return user;
} else if (BCrypt.checkpw(password, user.password)) {
return user;
} else {
return null;
}
}
}
authenticate()接收的是明文密码。上面的验证中,首先检查用户邮箱是否存在。如果存在,则检查密码是否符合数据库的记录。如果邮箱或者密码错误,将返回null。否则返回正确的用户对象。
我进一步修改控制器Application。这一次还是增加两个动作和一个表单类。动作login()用于显示登录页面,动作postLogin()用于处理登录表单填写的信息,并根据信息决定是否登入用户。Login类对应登录页面的表单。
package controllers; import play.*;
import play.mvc.*; import play.data.Form;
import play.data.validation.Constraints.*; import models.User; public class Application extends Controller { public static class Registration {
public String email;
@Required
public String password;
} public static Result register() {
Form<Registration> userForm = Form.form(Registration.class);
return ok(views.html.register.render(userForm));
} public static Result postRegister() {
Form<Registration> userForm =
Form.form(Registration.class).bindFromRequest();
User user = new User(userForm.get().email, userForm.get().password);
user.save();
return ok("registered");
} public static class Login {
public String email;
@Required
public String password; public String validate() {
if (User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
} public static Result login() {
Form<Login> userForm = Form.form(Login.class);
return ok(views.html.login.render(userForm));
} public static Result postLogin() {
Form<Login> userForm = Form.form(Login.class).bindFromRequest();
if (userForm.hasErrors()) {
return badRequest("Wrong user/password");
} else {
return ok("Valid user");
}
}
}
上面的表单类Login中,增加了validate()方法,并在其中调用User的验证逻辑。正如postLogin()中所示,表单的hasErrors()方法将自动检查validate()方法的返回值。如果validate()方法返回为null,则说明表单无误。postLogin()的if结构,将根据登录是否合法,来返回不同的结果。
为新增的动作增加对应的URL:
GET /login controllers.Application.login()
POST /login controllers.Application.postLogin()
访问/login页面,并尝试登录。
会话
HTTP协议是无状态的。即使我在/login登录成功,但下一次访问时,服务器又会忘记我是谁。HTTP协议可以用会话(Session)的方式,来记录用户的登录信息。在会话有效期内,服务器可以识别相应客户的访问。Play实现会话相当方便。
提交登录表格时,如果登录合法,我将让服务器开启和该客户的会话,记录客户的信息。因此,修改postLogin()为:
public static Result postLogin() {
Form<Login> userForm = Form.form(Login.class).bindFromRequest();
if (userForm.hasErrors()) {
return badRequest(views.html.login.render(userForm));
} else {
session().clear();
session("email",userForm.get().email);
return redirect("/");
}
}
这里用户登录成功后,将启动一个会话。在会话中,可放入键值对(key-value pair)形式的信息。这里的键名为"email",对应值为登录用户的邮箱地址。登录成功后将重新定向到/。
增加index()动作,对应/这一URL。在该动作中,我调用session中保存的用户信息:
public static Result index() {
String email = session("email");
if (email != null) {
return ok(email);
} else {
return ok("not login");
}
}
增加routes中对应的URL:
GET / controllers.Application.index()
访问/login,并登录。成功登录后重新定向到/,页面为:

可以看到,会话中的信息可以持续到以后的页面访问。为了销毁会话,可以在某个动作中调用:
session().clear();
总结
用户验证
会话
欢迎继续阅读“Java快速教程”系列文章
来玩Play框架06 用户验证的更多相关文章
- Play框架的用户验证。
最近刚刚参与一个基于Play框架的管理平台的升级工作,其中涉及到了用户的验证工作.第一次接触play框架,直接看已有代码,有点晕.因此,自己实现了一个简单的用户验证功能. 首先,新建一个User类,包 ...
- Django用户验证框架
一 分析源码 User Django的标准库存放在 django.contrib 包中.每个子包都是一个独立的附加功能包. 这些子包一般是互相独立的,不过有些django.contrib子包需要 ...
- php-laravel框架用户验证(Auth)模块解析(一)
一.初始化 使用php artisan命令进行初始化:php artisan make:auth 和 php artisan migrate(该命令会生成users表.password_resets表 ...
- spring4.0整合mongodb3.0.4项目实践(用户验证)
我们的项目用到了spring框架和mongdb数据库,随着mongodb升级到3.0已有半年时间,我们也开始随之升级,但是3.0的用户验证有所更改,导致原来的很多配置无法再用. 经过几天的尝试后,终于 ...
- php用户验证代码的简单例子
发布:sunday01 来源:net [大 中 小] 分享一个简单的php用户验证代码,适合初学的朋友参考,主要学习$_post传递数据及isset检测变量的方法. php简单用户验证代码 ...
- 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(五)——实现注册功能
使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...
- 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用
使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...
- 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(三)——使用Flask-Login库实现登录功能
使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...
- Laravel 5.3 用户验证源码探究 (一) 路由与注册
https://blog.csdn.net/realghost/article/details/52558962 简介 Laravel 从 5.2 开始就有了开箱即用的用户验证,5.3 又在 5.2 ...
随机推荐
- UVA, 10336 Rank the Languages
难点在于:递归函数和输出: #include <iostream> #include <vector> #include <algorithm> #include ...
- cesium自定义气泡窗口infoWindow
一.自定义气泡窗口与cesium默认窗口效果对比: 1.cesium点击弹出气泡窗口显示的位置固定在地图的右上角,默认效果: 2.对于习惯arcgis或者openlayer气泡窗口样式的giser来说 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- 从史上八大MySQL事故中学到的经验
本文列举了史上八大MySQL宕机事件原因.影响以及人们从中学到的经验,文中用地震级数来类比宕机事件的严重性和后果,排在最严重层级前两位的是由于亚马逊AWS宕机故障(相当于地震十级和九级). 一.Per ...
- Oracle中的commit详解
本文转自 : http://blog.csdn.net/hzhsan/article/details/9719307 它执行的时候,你不会有什么感觉.commit在数据库编程的时候很常用,当你执行DM ...
- mysql 赋予用户权限
# 赋予权限MySQL> grant 权限参数 on 数据库名称.表名称 to 用户名@用户地址 identified by '用户密码'; # 立即生效权限MySQL> flush pr ...
- VisualStudio 2015 开启IIS Express可以调试X64项目
现在项目开发时总有时需要在X64下开发,这样我们就需要IIS Express中调试.不要总是放在IIS中,在Attach这样好慢. 如果不设置直接调试X64的程序,我们有可能会受到以下类似的错误 ...
- Spring WebService入门
Web service是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布 ...
- EMD分析 Matlab 精华总结 附开源工具箱(全)
前言: 本贴写于2016年12与15日,UK.最近在学习EMD(Empirical Mode Decomposition)和HHT(Hilbert-Huang Transform)多分辨信号处理,FQ ...
- NodeJs 开发微信公众号(三)微信事件交互
微信公众号有个规则,一旦开启了开发者模式,其他的常规功能就都必须通过接口调用完成.比如说自定义菜单功能,必须通过发送post请求的方式生成.本章就通过关注到取消关注的整个过程来谈一谈nodejs是怎么 ...