Some My Experiences

Header Ads

Showing posts with label React. Show all posts
Showing posts with label React. Show all posts

Saturday 19 January 2019

Simple Authentication in React

This section describe how to implement authentication in React.

First, we need to create React app using this command:
npx create-react-app my-app
We also need to install React Router DOM using command:
npm install --save react-router-dom

Create file src/AppComponent/Authentication.js
This class will handle authentication.
isAuthentication() function will return boolean value whether user has been authenticated.
checkCredentials() function will check whether given credential is valid. For this example, checkCredentials() function use static user data. We need to change this function to use programmatic user data using user service.
setUserDetails() function is used to store user details. In this example, user details will saved to local storage.
class Authentication {
    static isAuthenticated = () => {
        return Authentication.getUser() !== null;
    }
    
    static authenticate = (credentials) => {
        if(credentials
            && credentials.username
            && credentials.password) {
                const isValidCredentials = Authentication.checkCredentials(credentials);
                if(isValidCredentials) {
                    Authentication.setUserDetails(credentials);
                }
                return isValidCredentials;
        }
        return false;
    }
    
    static checkCredentials = (credentials) => {
        return credentials.username == "admin" && credentials.password == "123";
    }
    
    static getUsername = (userDetails) => {
        return Authentication.getUser().username;
    }
    
    static setUserDetails = (userDetails) => {
        localStorage.setItem("user", JSON.stringify(userDetails));
    }

    static getUser = () => {
        return JSON.parse(localStorage.getItem("user"));
    }

    static logOut = () => {
        localStorage.removeItem("user");
    }
}

export default Authentication;

Create file src/AppComponent/AnonymousRoute.js
Use this class on pages that can only be visited by users who have not been authenticated, like login and reset password. If someone has been authenticated try to enter login page, this component will redirect user to root page. So, authenticated user will not face that page.
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import Authentication from './Authentication';

class AnonymousRoute extends Component {
    render() {
        const {component: Component, ...others} = this.props;
        
        const renderRoute = props => {
            if (Authentication.isAuthenticated()) {
                return (
                    <Redirect to={
                        {
                            pathname: '/'
                        }
                    } />
                );
            }
            return ( <Component {...props} /> );
        }

        return (
            <Route {...others} render={renderRoute}/>
        );
    }
}

export default AnonymousRoute;


Create file src/AppComponent/ProtectedRoute.js
Use this class on pages that can only be visited by users who have been authenticated, like profile page etc. If someone has not been authenticated try to enter protected resource/page, this component will redirect user to login page. This class will hold return url (actual user requested url before redirect to login) on state and will redirect user to requested url if authentication is success.
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import Authentication from './Authentication';

class ProtectedRoute extends Component {
    render() {
        const {component: Component, ...others} = this.props;
        
        const renderRoute = props => {
            if (Authentication.isAuthenticated()) {
                return ( <Component {...props} /> );
            }

            return (
                <Redirect to={
                    {
                        pathname: '/login', 
                        state: { returnUrl: props.location }
                    }
                } />
            );
        }

        return (
            <Route {...others} render={renderRoute}/>
        );
    }
}

export default ProtectedRoute;


Create file src/views/Home.js
This class will render Home Page that contain navigation to profile page and logout button if user has been authenticated, login page if user has not been authenticated.
import React, { Component } from 'react';
import Authentication from '../AppComponent/Authentication';
import { Link } from 'react-router-dom';

class Home extends Component {
    constructor(props) {
        super(props);
    }
    
    logout =(e) => {
        Authentication.logOut();
        this.props.history.push('/login');
    }

    render() {
        const navigation = Authentication.isAuthenticated()
            ? (<div><Link to="/profile">Profile Page</Link><br /><button onClick={() => this.logout() }>Logout</button></div>)
            : <Link to="/login">Login Page</Link>;
        
            return (
            <React.Fragment>
                <div>This is Home Page</div>
                { navigation }
            </React.Fragment>
        );
    }
}

export default Home;

views/Login.js
This class will render login page.
import React, { Component } from 'react';
import Authentication from '../AppComponent/Authentication';

class Login extends Component {
    constructor(props) {
        super(props);
        this.loginForm = React.createRef();
        this.state = {
            isLoginSuccess: true
        }
    }

    doLogin = () => {
        const form = this.loginForm.current;
        const credentials = {
            username: form.username.value,
            password: form.password.value
        }
        const isLoginSuccess = Authentication.authenticate(credentials);
        this.setState({ isLoginSuccess });
        if(!isLoginSuccess){ return; }

        let successUrl = this.props.location.state ? this.props.location.state.returnUrl : '/';
        this.props.history.push(successUrl);
    }

    render() {
        return (
            <React.Fragment>
                <div>
                    This is Login Page
                </div>
                <div>
                    <form ref={this.loginForm} onSubmit={(e)=> { e.preventDefault(); this.doLogin() }} >
                        <input type="text" name="username" placeholder="username" /><br />
                        <input type="password" name="password" placeholder="password" /><br />
                        <input type="submit" value="Submit" />
                    </form>
                    <div>{this.state.isLoginSuccess ? '' : 'Login fail.'}</div>
                </div>
            </React.Fragment>
        );
    }
}

export default Login;


Create file sec/views/Profile.js
This class will render profil page, and displays the name of the user who has logged in.
import React, { Component } from 'react';
import Authentication from '../AppComponent/Authentication';

class Profile extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                This is Profile Page.<br />
                Login as { Authentication.getUsername() }
            </div>
        );
    }
}

export default Profile;


Create file src/App.js
In this class, we use AnonymousRoute and ProtectedRoute components. Login page use AnonymousRoute, can only be seen by users who have not been authenticated. Profile page use ProtectedRoute, can only be seen by users who have been authenticated.
import React, { Component } from 'react';

import {
  Route,
  BrowserRouter, 
  Switch 
} from 'react-router-dom';

import Login from './views/Login';
import Profile from './views/Profile';
import Home from './views/Home';

import ProtectedRoute from './AppComponent/ProtectedRoute';
import AnonymousRoute from './AppComponent/AnonymousRoute';

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Switch>
          <AnonymousRoute exact path="/login" name="Login" component={Login} />
          <ProtectedRoute path="/profile" name="Profile" component={Profile} />
          <Route exact path="/" name="Home" component={Home} />
        </Switch>
      </BrowserRouter>
    );
  }
}

export default App;

To run app, we can execute command:
npm start

Source code can be found here: GitHub
React Version : 16.7.0