Authentication function with Play Framework [Registration and authentication]

When creating a web application, you often want to register user information and restrict page access. This time, I implemented the authentication function using Play Framework. The source can be found on GitHub.

environment

Functions to be realized

--Authentication by registering and collating user information --Access restrictions to the home screen (Next post) --Transfer of authentication authority when the same user as the authenticating user signs in from another browser (Next post)

Screen list

--Sign-up screen --Sign-in screen

file organization

  PlayAuthentication
     ├── app
     │   ├── common
     │   │   ├── global
     │   │   │   └── AppActionCreator.java
     │   │   └── secure
     │   │       └── AppAuthenticator.java
     │   ├── controllers
     │   │   ├── AppController.java
     │   │   ├── IndexController.java
     │   │   ├── SigninController.java
     │   │   └── SignupController.java
     │   ├── forms
     │   │   ├── AppForm.java
     │   │   ├── SigninForm.java
     │   │   └── SignupForm.java
     │   ├── models
     │   │   ├── AppModel.java
     │   │   └── User.java
     │   └── views
     │       ├── index.scala.html
     │       ├── main.scala.html
     │       ├── signin.scala.html
     │       └── signup.scala.html
     ├── build.sbt
     ├── conf
     │   ├── application.conf
     │   ├── evolutions
     │   │   └── default
     │   │       └── 1.sql
     │   └── routes
     └── project
         └── plugins.sbt

I think that the file name somehow conveys the role.

Database preparation

Register the user information entered from the sign-up screen in the DB. On the sign-in screen, enter your e-mail address and password and verify with the DB information to authenticate. I would like to store the entered user information in the H2DB of the in-memory database. I would like to use Ebean, which is compatible with Play, for the O / R mapper, and Evolutions for database management. To use H2DB, Ebean, and Evolutions, modify the following three points and reload and update sbt.

build.sbt


lazy val root = (project in file(".")).enablePlugins(PlayJava, PlayEbean) //Added PlayEbean

libraryDependencies += evolutions //add to

project/plugins.sbt


addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0") //add to

conf/application.conf


db {
  default.driver = org.h2.Driver
  default.url="jdbc:h2:mem:play;MODE=MYSQL" #This time MySQL mode
  default.username = sa
  default.password = ""
}

ebean {
  default = ["models.*"]
}

Then create a Java object Model class that holds the database information with the models package. I would like to create a superclass in the Model class and define the creation date and time and the last update date and time for all tables. This time, only the User table is created, so it doesn't make much sense.

AppModel.java


package models;

//import statement omitted

@MappedSuperclass
public abstract class AppModel extends Model {

	/** ID */
	@Id
	public Long id;
	
	/**Creation date and time*/
	@CreatedTimestamp
	public LocalDateTime created;
	
	/**Last Modified*/
	@UpdatedTimestamp
	public LocalDateTime updated;
	
}

User.java


package models;

//import statement omitted

@Entity
public class User extends AppModel {
	
	/**name*/
	public String name;

	/**mail address*/
	public String email;

	/**password*/
	public String password;
	
	/**Last login date and time*/
	public LocalDateTime logined;
	
}

At this point, start the server and access it. Then you will see the following screen in your browser.
evolutions.png

If you press the "Apply this script now!" Button as it is, SQL will be executed and a table will be created in H2DB. In addition, the following SQL files will be generated in conf / evolutions / default.

1.sql


# --- Created by Ebean DDL
# To stop Ebean DDL generation, remove this comment and start using Evolutions

# --- !Ups

create table user (
  id                            bigint not null,
  name                          varchar(255),
  email                         varchar(255),
  password                      varchar(255),
  logined                       timestamp,
  created                       timestamp not null,
  updated                       timestamp not null,
  constraint pk_user primary key (id)
);
create sequence user_seq;


# --- !Downs

drop table if exists user;
drop sequence if exists user_seq;

This seems to be raising the schema by looking at the Model class that is annotating the javax.persistence.Entity.

Registration and verification of user information

Now that we have confirmed that the database has been created, the next step is to create a screen for signing up and signing in. Create a View and Form respectively, and give the item an email address and password. I also gave the sign-up a name. This time, the source of View and Form is simple, so I will omit it. If you are interested, please refer to GitHub. Also, please refer to Post written about View and Form in Realization of vlidation function.

After that, the controller processes using the information input from the screen. The sign-up screen controller saves your name, email address, and password in the DB as user information.

SignupController.java


package controllers;

//import statement omitted

@Singleton
public class SignupController extends AppController {
	@Inject
	public SignupController(CacheApi cache) {
		super(cache);
	}
	@Inject
	private FormFactory formFactory;
	
	@Override
	public Result get() {
		Form<SignupForm> form = formFactory.form(SignupForm.class);
		return ok(views.html.signup.render(form));
	}

	@Override
	public Result post() {
		Form<SignupForm> form = formFactory.form(SignupForm.class).bindFromRequest();
		if(form.hasErrors()){
			return badRequest(views.html.signup.render(form));
		}
		
		try{
			/*
			 *Register new user information.
			 */
			Ebean.beginTransaction();
			User user = new User();
			user.name = form.get().name;
			user.email = form.get().email;
			user.password = BCrypt.hashpw(form.get().password, BCrypt.gensalt());
			user.logined = LocalDateTime.now();
			Ebean.insert(user);
			Ebean.commitTransaction();
			new SigninController(cache).setCacheUser(user);
		}catch(Exception e){
			Ebean.rollbackTransaction();
			return badRequest(views.html.signup.render(form));
		}finally {
			Ebean.endTransaction();
		}
		
		return redirect(routes.IndexController.get());
	}

}

The sign-in screen controller updates the login date and time of the user with the entered email address.

SigninController.java


package controllers;

//import statement omitted

@Singleton
public class SigninController extends AppController {
	@Inject
	private FormFactory formFactory;
	/**User information key*/
	public static final String USER_KEY = "USER";
	
	@Inject
	public SigninController(CacheApi cache) {
		super(cache);
	}

	@Override
	public Result get() {
		Form<SigninForm> form = formFactory.form(SigninForm.class);
		return ok(views.html.signin.render(form));
	}

	@Override
	public Result post() {
		Form<SigninForm> form = formFactory.form(SigninForm.class).bindFromRequest();
		if(form.hasErrors()){
			return badRequest(views.html.signin.render(form)); 
		}
		
		try{
			/*
			 *Update the user's login date and time.
			 */
			Ebean.beginTransaction();
			User user = Ebean.find(User.class).where().eq("email", form.get().email).findUnique();
			user.logined = LocalDateTime.now();
			Ebean.update(user);
			Ebean.commitTransaction();
			setCacheUser(user);
		}catch(Exception e){
			Ebean.rollbackTransaction();
			return badRequest(views.html.signin.render(form)); 
		}finally {
			Ebean.endTransaction();
		}
	
		return redirect(routes.IndexController.get());
	}
	

	/*
	 *The following methods are omitted
	 */
	
}

When saving user information on the sign-up screen controller, BCrypt is used to hash the password.

build.sbt


libraryDependencies += "org.mindrot" % "jbcrypt" % "0.4" //add to

After writing, please relaod and update sbt again.

Finally

This time I wrote about the part necessary to register and collate user information. I felt that there were many parts that I found useful for database management and operation rather than authentication. Access restrictions not written this time are written in here. GitHub

Recommended Posts

Authentication function with Play Framework [Registration and authentication]
Authentication function in Play Framework [Access restrictions]
Java to play with Function
Validation function in Play Framework
Implemented authentication function with Spring Security ②
Implemented authentication function with Spring Security ③
Double submit measures with Play Framework
Implemented authentication function with Spring Security ①
Play framework scheduled jobs and crontab
How to use BootStrap with Play Framework
Implement login, user registration, and two-factor authentication with Docker x Laravel 8 Jetstream
Play Framework study
[Introduction to Spring Boot] Authentication function with Spring Security
Handle JSON in cross domain with Play Framework
[Rails] Implementation of drag and drop function (with effect)
Play with Java function nodes that can use Java with Node-RED
Play Framework2.5 (Java) Tips
Play Framework studying test
With Spring boot, password is hashed and member registration & Spring security is used to implement login function.
play framework personal notes
With Kotorin ―― 7. Scoping Function
Serverless Function with Micronaut
[PHP8] Install and use PECL YAML function (YAML parser) with Docker
I want to make a function with kotlin and java!
[Java] [Play Framework] Until the project is started with Gradle
Implement login function simply with name and password in Rails (3)
Implement user registration function and corporate registration function separately in Rails devise
Visualize with BI tools by linking Asakusa Framework and Impala
A story about using the CoreImage framework to erase stains with Swift and implement a blur erase function