作者: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 {
@Email
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 {
@Email
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 {
@Email
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 用户验证的更多相关文章

  1. Play框架的用户验证。

    最近刚刚参与一个基于Play框架的管理平台的升级工作,其中涉及到了用户的验证工作.第一次接触play框架,直接看已有代码,有点晕.因此,自己实现了一个简单的用户验证功能. 首先,新建一个User类,包 ...

  2. Django用户验证框架

    一  分析源码 User   Django的标准库存放在 django.contrib 包中.每个子包都是一个独立的附加功能包. 这些子包一般是互相独立的,不过有些django.contrib子包需要 ...

  3. php-laravel框架用户验证(Auth)模块解析(一)

    一.初始化 使用php artisan命令进行初始化:php artisan make:auth 和 php artisan migrate(该命令会生成users表.password_resets表 ...

  4. spring4.0整合mongodb3.0.4项目实践(用户验证)

    我们的项目用到了spring框架和mongdb数据库,随着mongodb升级到3.0已有半年时间,我们也开始随之升级,但是3.0的用户验证有所更改,导致原来的很多配置无法再用. 经过几天的尝试后,终于 ...

  5. php用户验证代码的简单例子

    发布:sunday01   来源:net     [大 中 小] 分享一个简单的php用户验证代码,适合初学的朋友参考,主要学习$_post传递数据及isset检测变量的方法. php简单用户验证代码 ...

  6. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(五)——实现注册功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  7. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  8. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(三)——使用Flask-Login库实现登录功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  9. Laravel 5.3 用户验证源码探究 (一) 路由与注册

    https://blog.csdn.net/realghost/article/details/52558962 简介 Laravel 从 5.2 开始就有了开箱即用的用户验证,5.3 又在 5.2 ...

随机推荐

  1. 推荐一个ASP.NET网站内容管理系统源码

    许多人都有各自的兴趣,如打球.踢毽子.看书.看电视.玩游戏等等....我近来迷上了猜灯谜,于是业余做了一个在线猜灯谜的网站:何问起谜语. 先出个谜语让你猜猜:不可缺一点(打一字).可以在线猜:http ...

  2. 【工具使用】mac电脑使用技巧

    本文地址 分享提纲: 1.  mac命令行和finder的交互 2. 一些mac的插件 3. 一些开发的配置 1.mac命令行和findder交互           1)命令行中打开当前文件夹: o ...

  3. SAP CRM 将组件整合至导航栏中

    到现在,我们已经可以让组件独立地显示.我们只是运行它.让它显示在Web UI中.让我们把组件整合进导航栏,使我们可以在正常登录Web UI时访问它. 步骤一: 为你的UI组件主窗体创建一个内向插件. ...

  4. Git快速入门

    如果你不想看长篇的Git教程,想快速了解Git的使用,那么本文可能会对你入门Git有所帮助.由于笔者用的是Windows系统,所以本文只写Git在Windows上的使用. 一.Git安装 去Git官网 ...

  5. 开始webservice了

    一.WebService到底是什么 一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用技术. 所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用 ...

  6. Spring.Net在Mvc4.0中应用的说明

    案例Demo:http://yunpan.cn/cJ5aZrm7Uybi3 访问密码 414b Spring.Net在Mvc4.0中应用的说明 1.引用dll 2.修改Global文件 (Spring ...

  7. [PHP源码阅读]trim、rtrim、ltrim函数

    trim系列函数是用于去除字符串中首尾的空格或其他字符.ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符. 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下 ...

  8. Oracle11g CentOS7安装记录

    1. 操作系统环境.安装包准备 宿主机:Max OSX 10.10.5 虚拟机:Parallel Desktop 10.1.1 虚拟机操作系统:CentOS-7-x86_64-DVD-1511.iso ...

  9. Python学习--03变量类型

    变量赋值 Python中的变量不需要声明,变量的赋值操作既是变量声明和定义的过程. 每个变量在内存中创建,都包括变量的标识,名称和数据这些信息. 每个变量在使用前都必须赋值,变量赋值以后该变量才会被创 ...

  10. Underscore.js

    概述 Underscore.js是一个很精干的库,压缩后只有4KB.它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了JavaScript的编程.MVC框架Backbone.js就将这个库 ...