首页 > 技术文章 > Play框架的用户验证。

junjiang3 2017-06-16 15:48 原文

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

首先,新建一个User类,包含两个属性,包含两个属性email和password。并在构造器中对密码进行了加密。

@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;
}
}

接下来,新增控制器Application.java,其中主要包含包含两个动作和一个表单类Registration。一个动作register()用于显示注册页面,另一个动作postRegister处理表单提交的信息,
并增加相应的数据库记录。Registration则对应注册页面所显示的表格:
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"); 
    }
}

其后,新增Rigister所对应的前端页面,并在Routes文件中为Appication所对应的动作增加访问路径。
<!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文件:
GET     /register                   controllers.Application.register()
POST    /register                   controllers.Application.postRegister()

其后,访问页面,输入用户名和密码,可以看到数据库中新增了一条记录。
接下来,将用户验证的逻辑加入到User类中,修改User类,新增authenticate()方法。authenticate()接收的是明文密码。上面的验证中,首先检查用户邮箱是否存在。如果存在,则检查密码是否符合数据库的记录。
如果邮箱或者密码错误,将返回null。否则返回正确的用户对象。
// 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;
        }
    }
接下来,进一步修改Application控制器,增加两个动作和一个表单类。动作login()用于显示登录页面,动作postLogin()用于处理登录表单填写的信息,并根据信息决定是否登入用户。Login类对应登录页面的表单。
 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结构,将根据登录是否合法,来返回不同的结果。

最后,同样的在Routes文件中新增两条对应的URL
GET     /login                      controllers.Application.login()
POST    /login                      controllers.Application.postLogin()

其后,访问/login页面,并尝试登录。发现已增加了验证功能。





推荐阅读