Here is the continued article on my previous post for creating a welcome with login and logout using ReactJS. Today’s post explains how to implement login authentication system for your React JS applications. It will show you how to log in with a user and store the user session, so it deals with token-based authentication. Since we are using token-based authentication, it protects if any unauthorized request is made and notices for a new login if required. This makes your application’s authentication to be more secure compared with any other authentication system. Every user details will be stored in an external database and a PHP based API is used in the backend for handling this authentication. Hope you’ll find it more easily using this as your authentication system in your ReactJS projects. Let’s look into the live demo and follow the below code.
Live Demo
Video Tutorial
ReactJS User Restful Authentication for Login and Signup
Database Design
To build the user feed system, you have to create two tables such as Users and Feed. You can check my previous tutorials for creating token-based API system.
Users
User table contains all the users registration details.
CREATE TABLE users(
user_id int AUTO_INCREMENT PRIMARY KEY,
username varchar(50),
password varchar(300),
name varchar(200),
email varchar(300));
user_id int AUTO_INCREMENT PRIMARY KEY,
username varchar(50),
password varchar(300),
name varchar(200),
email varchar(300));
Feed
This table contains user daily updates.
CREATE TABLE feed(
feed_id int PRIMARY KEY AUTO_INCREMENT,
feed text,
user_id_fk int
);
feed_id int PRIMARY KEY AUTO_INCREMENT,
feed text,
user_id_fk int
);
Download PHP Restul Project
$git clone https://github.com/srinivastamada/PHP-Slim-Restful.git
welcome.js
As explain in previous tutorial, just include Login and Signup component links.
import React, {Component} from 'react';
export default Welcome;
import './Welcome.css';
class Welcome extends Component {
render() {
return (
<div className="row " id="Body">
<div className="medium-12 columns">
<h2 id="welcomeText">Make people fall in love with your ideas</h2>
<a href="/login" className="button">Login</a>
<a href="/signup" className="button success">Signup</a>
</div>
</div>
);
}
}
Step 1 - Login.js
Designing Login component, here just include HTML for login form. Created constructor function with super properties for intitiating global this
import React, {Component} from 'react';
export default Login;
import './Login.css';
class Login extends Component {
constructor(){
super();
};
}
render() {
return (
<div className="row" id="Body">
<div className="medium-5 columns left">
<h4>Login</h4>
<label>Username</label>
<input type="text" name="username" placeholder="Username" />
<label>Password</label>
<input type="password" name="password" placeholder="Password" />
<input type="submit" className="button success" value="Login" />
<a href="/signup">Registration</a>
</div>
</div>
);
}
}
Step 2 - Login.js
In constructor function defined the state object for changing input fields. Login() function will communicate with RESTful API and onChange function set the state value based on the user input value.
import React, {Component} from 'react';
export default Login;
import './Login.css';
class Login extends Component {
constructor(){
super();
this.state = {
username: '',
password: '',
redirectToReferrer: false
};
this.login = this.login.bind(this);
this.onChange = this.onChange.bind(this);
}
login() {
//API Action Here
}
onChange(e){
this.setState({[e.target.name]:e.target.value});
}
render() {
return (
<div className="row" id="Body">
<div className="medium-5 columns left">
<h4>Login</h4>
<label>Username</label>
<input type="text" name="username" onChange={this.onChange}/>
<label>Password</label>
<input type="password" name="password" onChange={this.onChange}/>
<input type="submit" value="Login" onClick={this.login}/>
<a href="/signup">Registration</a>
</div>
</div>
);
}
}
PostData.js
In src/service create an export class for fetching RESTful calls and returns Promise.
export function PostData(type, userData) {
}
let BaseURL = 'https://api.thewallscript.com/restful/';
//let BaseURL = 'http://localhost/PHP-Slim-Restful/api/';
return new Promise((resolve, reject) =>{
fetch(BaseURL+type, {
method: 'POST',
body: JSON.stringify(userData)
})
.then((response) => response.json())
.then((res) => {
resolve(res);
})
.catch((error) => {
reject(error);
});
});
Final Login.js
Imported Redirect and PostData components. Login function set the state redirtion value to true, one the API is succesful. Based on the state.redirection value, the page will redirect to the home page.
import React, {Component} from 'react';
export default Login;
import {Redirect} from 'react-router-dom';
import {PostData} from '../../services/PostData';
import './Login.css';
class Login extends Component {
constructor(){
super();
this.state = {
username: '',
password: '',
redirectToReferrer: false
};
this.login = this.login.bind(this);
this.onChange = this.onChange.bind(this);
}
login() {
if(this.state.username && this.state.password){
PostData('login',this.state).then((result) => {
let responseJson = result;
if(responseJson.userData){
sessionStorage.setItem('userData',JSON.stringify(responseJson));
this.setState({redirectToReferrer: true});
}
});
}
}
onChange(e){
this.setState({[e.target.name]:e.target.value});
}
render() {
if (this.state.redirectToReferrer || sessionStorage.getItem('userData')){
return (<Redirect to={'/home'}/>)
}
return (
<div className="row" id="Body">
<div className="medium-5 columns left">
<h4>Login</h4>
<label>Username</label>
<input type="text" name="username" onChange={this.onChange}/>
<label>Password</label>
<input type="password" name="password" onChange={this.onChange}/>
<input type="submit" value="Login" onClick={this.login}/>
<a href="/signup">Registration</a>
</div>
</div>
);
}
}
PHP
This code contains login ang sigup function with PDO MySQL connetion and it works with Slim framework. Download this project from GitHub.
<?php
}
?>
require 'config.php';
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->post('/login','login'); /* User login */
$app->post('/signup','signup'); /* User Signup */
$app->post('/feed','feed'); /* User Feeds */
$app->post('/feedUpdate','feedUpdate'); /* User Feeds */
$app->post('/feedDelete','feedDelete'); /* User Feeds */
//$app->post('/userDetails','userDetails'); /* User Details */
$app->run();
/************************* USER LOGIN *************************************/
/* ### User login ### */
function login() {
$request = \Slim\Slim::getInstance()->request();
$data = json_decode($request->getBody());
try {
$db = getDB();
$userData ='';
$sql = "SELECT user_id, name, email, username FROM users WHERE (username=:username or email=:username) and password=:password ";
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $data->username, PDO::PARAM_STR);
$password=hash('sha256',$data->password);
$stmt->bindParam("password", $password, PDO::PARAM_STR);
$stmt->execute();
$mainCount=$stmt->rowCount();
$userData = $stmt->fetch(PDO::FETCH_OBJ);
if(!empty($userData))
{
$user_id=$userData->user_id;
$userData->token = apiToken($user_id);
}
$db = null;
if($userData){
$userData = json_encode($userData);
echo '{"userData": ' .$userData . '}';
} else {
echo '{"error":{"text":"Bad request wrong username and password"}}';
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
/* ### User registration ### */
function signup() {
$request = \Slim\Slim::getInstance()->request();
$request = \Slim\Slim::getInstance()->request();
$data = json_decode($request->getBody());
$email=$data->email;
$name=$data->name;
$username=$data->username;
$password=$data->password;
try {
$username_check = preg_match('~^[A-Za-z0-9_]{3,20}$~i', $username);
$email_check = preg_match('~^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.([a-zA-Z]{2,4})$~i', $email);
$password_check = preg_match('~^[A-Za-z0-9!@#$%^&*()_]{6,20}$~i', $password);
if (strlen(trim($username))>0 && strlen(trim($password))>0 && strlen(trim($email))>0 && $email_check>0 && $username_check>0 && $password_check>0)
{
$db = getDB();
$userData = '';
$sql = "SELECT user_id FROM users WHERE username=:username or email=:email";
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username,PDO::PARAM_STR);
$stmt->bindParam("email", $email,PDO::PARAM_STR);
$stmt->execute();
$mainCount=$stmt->rowCount();
$created=time();
if($mainCount==0)
{
/*Inserting user values*/
$sql1="INSERT INTO users(username,password,email,name)VALUES(:username,:password,:email,:name)";
$stmt1 = $db->prepare($sql1);
$stmt1->bindParam("username", $username,PDO::PARAM_STR);
$password=hash('sha256',$data->password);
$stmt1->bindParam("password", $password,PDO::PARAM_STR);
$stmt1->bindParam("email", $email,PDO::PARAM_STR);
$stmt1->bindParam("name", $name,PDO::PARAM_STR);
$stmt1->execute();
$userData=internalUserDetails($email);
}
$db = null;
if($userData){
$userData = json_encode($userData);
echo '{"userData": ' .$userData . '}';
} else {
echo '{"error":{"text":"Enter valid data"}}';
}
}
else{
echo '{"error":{"text":"Enter valid data"}}';
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
?>
Previous Tutorial: ReactJS Welcome Page with Routing Tutorial
good tutorial
ReplyDeleteThx awesome tutorials always
ReplyDeleteGood info., Thanks
ReplyDeleteWow nice and informative article sir thanks for sharing
ReplyDeleteplease show structure file json https://api.thewallscript.com/restful/
ReplyDeletehow to run this project,i try run with npm. this project can be run but login and registration dosen't work
ReplyDeleteif we need to call with headers in API call with some token value? What will be the call?
ReplyDeletehow to configure Slim framework set content type, As i am getting an error 400 of not setting up content type?
ReplyDeleteThank you for these tutorial sir,for me delete response showing in react positively but when i checked in mysql feed is not deleted.
ReplyDeleteHmmmm, your code is just comparing if the tokens match, which to me is not "secure" because anybody can easily get the token value base on the response from the API and use it to submit a JSON data to the API using the token value and exactly the same request headers.
ReplyDeleteits awesome article i like it.
ReplyDeleteUnhandled Rejection (SyntaxError): Unexpected end of JSON input
ReplyDelete!! help pleas
its awesome article i like it
ReplyDeleteI know this is a little late, but maybe can help others that run into this. I had this problem as well, and found (in my case) that I was returning a non-json response (from my API server).
ReplyDeletethanks sir for this article but is there a python version for login and signup functions ?
ReplyDeleteawesome tutorial
ReplyDeleteI changed the sessionStorage to localStorage..
ReplyDeletebut there's 400 request, even tho the username and the password is correct and the server is python with django framework. Any tip?
Thanks
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete