Authentication and authorization using react.js and asp.net core

21 minute read

In the previous article, I have shown you how to create a back end application for authentication and authorization using JWT and .net core. In this article, I will design UI using react.js. I will also show you how to maintain authentication and authorization from front end.

Step 1: Create a sample react application

  • Create a react app name - ecommerce.client using the following command.
    npx create-react-app my-app
    
  • Apply required bootstrap theme on it.

Step 2: Create config.js in public/assets folder

config.js

var baseURL = "https://localhost:7142/";

Step 3: Include config.js in public/index.html file

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React::Auth</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->

    <script src="%PUBLIC_URL%/assets/config.js"></script>
  </body>
</html>

Step 4: Create components in src folder

  • Create AccessAPI and Settings Components in src->components->services folder

Settings.js

export const BASE_URL = window.baseURL;

AccessAPI.js


import SessionManager from "../Auth/SessionManager";
import { BASE_URL } from "./Settings";


export function getData(endPoint) {

    let token=SessionManager.getToken();

    let payload = {
        method: 'GET',
        headers: {   
            "access-control-allow-origin" : "*", 
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token
         },
    }
    return fetch(BASE_URL + endPoint, payload)
    .then(function(response) {
        if (!response.ok) {
            throw Error(response.statusText);
        }
        return response.json();
    }).then(function(result) {
        return result;
    }).catch(function(error) {
        console.log(error);
    });
}

export function postDataForLogin(type, userData) {
    //let BaseURL = "https://localhost:7142/";
    let payload = {
        method: 'POST',
        headers: {   
            "access-control-allow-origin" : "*",
            'Content-Type': 'application/json' 
        },
        body: JSON.stringify(userData)

    }
    return fetch(BASE_URL + type, payload)
    .then(function(response) {
        return response.json();
    }).then(function(result) {
        return result;
    }).catch(function(error) {
        console.log(error);
    });
}

export function postData(endPoint, inputObj) {
    let token=SessionManager.getToken();
    let payload = {
        method: 'POST',
        headers: {   
            "access-control-allow-origin" : "*", 
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token
        },
        body: JSON.stringify(inputObj)

    }
    return fetch(BASE_URL + endPoint, payload)
    .then(function(response) {
        return response.json();
    }).then(function(result) {
        return result;
    }).catch(function(error) {
        console.log(error);
    });
}

export function deleteData(endPoint) {
    let token=SessionManager.getToken();
    let payload = {
        method: 'DELETE',
        headers: {   
            "access-control-allow-origin" : "*", 
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token
         },
    }
    return fetch(BASE_URL + endPoint, payload)
    .then(function(response) {
        if (!response.ok) {
            throw Error(response.statusText);
        }
        return response.json();
    }).then(function(result) {
        return result;
    }).catch(function(error) {
        console.log(error);
    });
}

export function putData(endPoint, obj) {
    let token=SessionManager.getToken();
    let payload = {
        method: 'PUT',
        headers: {   
            "access-control-allow-origin" : "*", 
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token
        },
        body: JSON.stringify(obj)

    }
    return fetch(BASE_URL + endPoint, payload)
    .then(function(response) {
        return response.json();
    }).then(function(result) {
        return result;
    }).catch(function(error) {
        console.log(error);
    });
}
  • Create Login, Logout and SessionManager component in src->components->Auth folder

Login.js

import { Component } from "react";
import { toast, ToastContainer } from "react-toastify";
import 'react-toastify/dist/ReactToastify.css';
import { Container } from "reactstrap";
import LoginMenu from "../LoginMenu";
import { postDataForLogin } from "../services/AccessAPI";
import SessionManager from "./SessionManager";


export default class Login extends Component {
    constructor() {
        super();
        this.state = {
            userName: "",
            password: "",
            loading: false,
            failed: false,
            error: ''
        };

        this.login = this.login.bind(this);
        this.onChange = this.onChange.bind(this);
    }


    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }

    onKeyDown = (e) => {
        if (e.key === 'Enter') {
            this.login();
        }
    }

    login() {
        let userInfo = this.state;
        this.setState({
            loading: true
        });

        //console.log("login info: " + userInfo.password);
        postDataForLogin('api/Auth/Login', userInfo).then((result) => {
            if (result?.token) {

                SessionManager.setUserSession(result.userName, result.token, result.userId, result.usersRole)

                if (SessionManager.getToken()) {
                    this.setState({
                        loading: false
                    });

                    // <LoginMenu menuText = 'Logout' menuURL = '/logout' />

                    // If login successful and get token
                    // redirect to dashboard
                    window.location.href = "/home";
                }
            }

            else {
                let errors = '';
                for (const key in result?.errors) {
                    if (Object.hasOwnProperty.call(result.errors, key)) {
                        errors += result.errors[key];

                    }
                }
                errors = errors === '' ? 'Login is unsuccessfull!' : errors;
                toast.error(errors, {
                    position: "top-right",
                    autoClose: 5000,
                    hideProgressBar: true,
                    closeOnClick: true,
                    pauseOnHover: true,
                    draggable: true
                });

                this.setState({
                    errors: "Login failed!",
                    loading: false
                });
            }

        });
    }

    registration(){
        window.location.href = "/admin/user/register";

    }

    render() {
        let content;
        if (this.state.loading) {
            content = <div>Loading...</div>;
        }

        return (
            <div className="row" style=>
            <div className="login-box col-md-4">
                <div className="login-logo">
                    <a href="/"><b>ECommerce</b></a>
                </div>
                <div className="login-box-body">
                    <p className="login-box-msg">Sign in to access the application</p>

                    <div className="form-group has-feedback">
                        <input
                            type="text"
                            className="form-control"
                            placeholder="Please Enter Username"
                            name="userName"
                            onChange={this.onChange}
                            onKeyDown={this.onKeyDown}
                        />
                        <span className="glyphicon glyphicon-user form-control-feedback" />
                    </div>
                    <div className="form-group has-feedback">
                        <input type="password" className="form-control" placeholder="Please Enter Password" name="password"
                            onChange={this.onChange} onKeyDown={this.onKeyDown}
                        />
                        <span className="glyphicon glyphicon-lock form-control-feedback" />
                    </div>
                    <div className="row">
                        <div className="col-md-4">
                            <button className="btn btn-primary btn-block" onClick={this.login}>
                                Sign In
                            </button>
                        </div>
                        <div className="col-md-6">
                            <button className="btn btn-primary btn-block" onClick={this.registration}>
                                Create an account
                            </button>
                        </div>
                        <div className="col-md-2">
                            {content}
                        </div>
                    </div>
                    <div className="row">
                        <div className="col-md-8" style=>
                            <strong className="has-error" style=>{this.state.errorMsg}</strong>
                        </div>
                        <div className="col-md-4">
                            <ToastContainer></ToastContainer>
                        </div>
                    </div>
                </div>
            </div>

            </div>
        );
    }
}

Logout.js


import { Component } from "react";
import SessionManager from "./SessionManager";

export default class Logout extends Component{
    constructor(){
        super();
        this.state = {

        }
    }

    componentDidMount(){
        console.log("component did mount for logout");
        SessionManager.removeUserSession();
        window.location.href = "/login";
    }

    render(){
        return(
            <div></div>
        );
    }

}

SessionManager.js


const SessionManager = {

    getToken() {
        const token = sessionStorage.getItem('token');
        if (token) return token;
        else return null;
    },

    setUserSession(userName, token, userId, usersRole) {
        sessionStorage.setItem('userName', userName);
        sessionStorage.setItem('token', token);
        sessionStorage.setItem('userId', userId);
        sessionStorage.setItem('usersRole', usersRole);
    },

    removeUserSession(){
        sessionStorage.removeItem('userName');
        sessionStorage.removeItem('token');
        sessionStorage.removeItem('userId');
        sessionStorage.removeItem('usersRole');
    }
}

export default SessionManager;

  • Create customers components in src->components->Customer folder

Create.jsx

import React, { Component } from "react";
import { postData } from "../services/AccessAPI";

export class Create extends Component {

    constructor(props) {
        super(props);
        this.state = {
            firstName: '',
            lastName: '',
            email: '',
            contactNumber: '',
            address: ''
        }

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }


    onSubmit(e) {
        e.preventDefault();
        const { history } = this.props;

        let customerObj = {
            firstName: this.state.firstName,
            lastName: this.state.lastName,
            email: this.state.email,
            contactNumber: this.state.contactNumber,
            address: this.state.address
        }


        postData('api/Customer/Create', customerObj).then((result) => {
            let responseJson = result;
            if (responseJson) {
                history.push('/banking/customers');
            }
        });
    }

    render() {
        return (
            <div className="row">
                <div className="col-md-4">
                    <h3>Add new customer</h3>
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <label className="control-label">First Name: </label>
                            <input className="form-control" type="text" name="firstName" value={this.state.firstName} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Last Name: </label>
                            <input className="form-control" type="text" name="lastName" value={this.state.lastName} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Email: </label>
                            <input className="form-control" type="text" name="email" value={this.state.email} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Contact Number: </label>
                            <input className="form-control" type="text" name="contactNumber" value={this.state.contactNumber} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Address:  </label>
                            <input className="form-control" type="text" name="address" value={this.state.address} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <input type="submit" value="Add Customer" className="btn btn-primary"></input>
                        </div>

                    </form>

                </div>
            </div>
        )
    }

}

Customers.jsx


import React, { Component } from 'react';
import { getData } from '../services/AccessAPI';

// export keyword is a new feature in ES6 let export your functions , 
// variables so you can get access to them in other js files

export class Customers extends Component {
    //“Props” is a special keyword in React, which stands for properties and is being used for passing data from one component to another.
    constructor(props) {

        //If you do not call super(props) method, this. props will be undefined 
        super(props);

        this.OncustomerEdit = this.OncustomerEdit.bind(this);
        this.OncustomerDelete = this.OncustomerDelete.bind(this);
        this.onCustomerCreate = this.onCustomerCreate.bind(this);

        this.state = {
            customers: [],
            loading: true,
            failed: false,
            error: ''
        }
    }

    /*Lifecycle Method: The componentDidMount() method runs after 
    the component output has been rendered to the DOM.*/

    componentDidMount() {
        this.populateCustomersData();
    }

    // Event handler for create button
    onCustomerCreate() {
        const { history } = this.props;
        history.push('/banking/customer/create');
    }

    // Event handler for edit button
    OncustomerEdit(id) {
        const { history } = this.props;
        history.push('/banking/customer/edit/' + id);
    }

    // Event handler for delete button
    OncustomerDelete(id) {
        const { history } = this.props;
        history.push('/banking/customer/delete/' + id);
    }

    populateCustomersData() {

        getData(`api/Customer/getall`).then(
            (result) => {
                let responseJson = result;
                if (responseJson) {
                    this.setState({
                        customers: responseJson,
                        loading: false
                    });
                }
            }
        );
    }

    renderAllCustomersTable(customers) {
        return (
            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>First Name</th>
                        <th>Last Name</th>
                        <th>Email</th>
                        <th>Contact Number</th>
                        <th>Address</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        customers.map(customer => (
                            <tr key={customer.id}>
                                <td>{customer.firstName}</td>
                                <td>{customer.lastName}</td>
                                <td>{customer.email}</td>
                                <td>{customer.contactNumber}</td>
                                <td>{customer.address}</td>
                                <td><button onClick={() => this.OncustomerEdit(customer.id)} className="btn btn-success">Edit</button> ||
                                    <button onClick={() => this.OncustomerDelete(customer.id)} className="btn btn-danger">Delete</button></td>
                            </tr>
                        ))
                    }
                </tbody>
            </table>
        );
    }

    render() {

        let content = this.state.loading ? (
            <p>
                <em>Loading...</em>
            </p>
        ) : (
            this.renderAllCustomersTable(this.state.customers)
        )

        return (
            <div>
                <h2>Customer</h2>
                <button onClick={() => this.onCustomerCreate()} className="btn btn-primary">Create</button>
                {content}
            </div>
        );
    }

}

_Edit.jsx


import React, { Component } from "react";
import { getData, putData } from "../services/AccessAPI";

export class Edit extends Component {
    constructor(props) {
        super(props);

        this.onChangeFirstName = this.onChangeFirstName.bind(this);
        this.onChangeLastName = this.onChangeLastName.bind(this);
        this.onChangeEmail = this.onChangeEmail.bind(this);
        this.onChangeContactNumber = this.onChangeContactNumber.bind(this);
        this.onChangeAddress = this.onChangeAddress.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state = {
            id: '',
            firstName: '',
            lastName: '',
            email: '',
            contactNumber: '',
            address: ''
        }
    }

    componentDidMount() {
        const { id } = this.props.match.params;
        this.getCustomer(id);
    }

    getCustomer(id) {
        getData('api/Customer/' + id).then(
            (result) => {
                if (result) {
                    this.setState({
                        id: result.id,
                        firstName: result.firstName,
                        lastName: result.lastName,
                        email: result.email,
                        contactNumber: result.contactNumber,
                        address: result.address
                        //loading: false
                    });
                }
            }
        );
    }

    onChangeFirstName(e) {
        this.setState({
            firstName: e.target.value
        });
    }

    onChangeLastName(e) {
        this.setState({
            lastName: e.target.value
        });
    }

    onChangeEmail(e) {
        this.setState({
            email: e.target.value
        });
    }

    onChangeContactNumber(e) {
        this.setState({
            contactNumber: e.target.value
        });

    }

    onChangeAddress(e) {
        this.setState({
            address: e.target.value
        });
    }


    onUpdateCancel() {
        const { history } = this.props;
        history.push('/banking/customers');
    }

    onSubmit(e) {

        e.preventDefault();
        const { history } = this.props;
        const { id } = this.props.match.params;
        let customerObj = {
            id: this.state.id,
            firstName: this.state.firstName,
            lastName: this.state.lastName,
            contactNumber: this.state.contactNumber,
            email: this.state.email,
            address: this.state.address
        }

        putData('api/Customer/Edit/' + id, customerObj).then((result) => {
            let responseJson = result;
            if (responseJson) {
                console.log(responseJson);
                history.push('/banking/customers');
            }
        }

        );
    }

    render() {
        return (
            <div className="row">
                <div className="col-md-4">
                    <h3>Edit Customer</h3>
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <label className="control-label">First Name: </label>
                            <input className="form-control" type="text" value={this.state.firstName} onChange={this.onChangeFirstName}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Last Name: </label>
                            <input className="form-control" type="text" value={this.state.lastName} onChange={this.onChangeLastName}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Email: </label>
                            <input className="form-control" type="text" value={this.state.email} onChange={this.onChangeEmail}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Contact Number: </label>
                            <input className="form-control" type="text" value={this.state.contactNumber} onChange={this.onChangeContactNumber}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Address: </label>
                            <input className="form-control" type="text" value={this.state.address} onChange={this.onChangeAddress}></input>
                        </div>

                        <div className="form-group">
                            <button onClick={this.onUpdateCancel} className="btn btn-default">Cancel</button>
                            <input type="submit" value="Edit" className="btn btn-primary"></input>
                        </div>

                    </form>

                </div>
            </div>
        )
    }
}

Delete.jsx


import React, { Component } from "react";
import { deleteData, getData } from "../services/AccessAPI";

export class Delete extends Component {
    constructor(props) {
        super(props);

        this.onCancel = this.onCancel.bind(this);
        this.onConfirmation = this.onConfirmation.bind(this);

        this.state = {
            firstName: '',
            lastName: '',
            email: '',
            contactNumber: '',
            address: ''
        }
    }

    componentDidMount() {
        const { id } = this.props.match.params;
        this.getCustomer(id);
    }

    getCustomer(id) {
        getData('api/Customer/' + id).then(
            (result) => {
                if (result) {
                    this.setState({
                        id: result.id,
                        firstName: result.firstName,
                        lastName: result.lastName,
                        email: result.email,
                        contactNumber: result.contactNumber,
                        address: result.address
                        //loading: false
                    });
                }
            }
        );
    }

    onCancel() {
        const { history } = this.props;
        history.push('/banking/customers');
    }

    onConfirmation(e) {
        e.preventDefault();

        const { id } = this.props.match.params;
        const { history } = this.props;

        deleteData('api/Customer/Delete/' + id).then((result) => {
            let responseJson = result;
            if (responseJson) {
                history.push('/banking/customers');
            }
        }
        );
    }


    render() {
        return (
            <div>
                <h2>Delete</h2>
                <h3>Are you sure you want to delete this?</h3>
                <div>
                    <h4>Customer</h4>
                    <dl class="row">
                        <dt class="col-sm-2">
                            First Name:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.firstName}
                        </dd>
                        <dt class="col-sm-2">
                            Last Name:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.lastName}
                        </dd>
                        <dt class="col-sm-2">
                            Email:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.email}
                        </dd>
                        <dt class="col-sm-2">
                            Contact Number:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.contactNumber}
                        </dd>

                        <dt class="col-sm-2">
                            Address:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.address}
                        </dd>

                    </dl>

                    <form onSubmit={this.onConfirmation}>
                        <input type="hidden" asp-for="Id" />
                        <button type="submit" class="btn btn-danger">Delete</button> |
                        <button onClick={this.onCancel} className="btn btn-primary">Back to List</button>
                    </form>
                </div>
            </div>
        )
    }
}

  • Create roles components in src->components->Role folder

CreateRole.js

import { Component } from "react";
import { postData } from "../services/AccessAPI";

export default class CreateRole extends Component{
    constructor(props){
        super(props);
        this.state = {
            roleName: '',
            loading: true
        };

        this.onSubmit = this.onSubmit.bind(this);
        this.onChange = this.onChange.bind(this);

    }

    onSubmit(e){
        e.preventDefault();
        const{history} = this.props;

        let roleObj = {
            roleName: this.state.roleName
        }

        postData('api/Role/Create', roleObj).then((result) => {
            let responseJson = result;

            if(responseJson){
                history.push('/admin/roles');
            }
        });
    }

    onChange(e){
        this.setState({[e.target.name]: e.target.value});
    }

    render(){
        return(
            <div className="row">
            <div className="col-md-4">
                <h3>Create new role</h3>
                <form onSubmit={this.onSubmit}>
                    <div className="form-group">
                        <label className="control-label">Role Name: </label>
                        <input className="form-control" type="text" name="roleName" value={this.state.roleName} onChange={this.onChange}></input>
                    </div>
                    <div className="form-group">
                        <input type="submit" value="Add Role" className="btn btn-primary"></input>
                    </div>

                </form>

            </div>
        </div>
        );
    }
}

DeleteRole.js


import React, { Component } from "react";
import { deleteData, getData } from "../services/AccessAPI";

export class DeleteRole extends Component {
    constructor(props) {
        super(props);

        this.onCancel = this.onCancel.bind(this);
        this.onConfirmation = this.onConfirmation.bind(this);

        this.state = {
            roleName: '',
            loading: true
        }
    }

    componentDidMount() {
        const { id } = this.props.match.params;

        getData('api/Role/' + id).then(
            (result) => {
                console.log("Role for edit: ");
                console.log(result);
                if (result) {
                    this.setState({
                        id: result.id,
                        roleName: result.roleName,
                        loading: false
                    });
                }
            }
        );
    }

    onCancel() {
        const { history } = this.props;
        history.push('/admin/roles');
    }

    onConfirmation(e) {
        e.preventDefault();

        const { id } = this.props.match.params;
        const { history } = this.props;

        deleteData('api/Role/Delete/' + id).then((result) => {
            let responseJson = result;
            if (responseJson) {
                console.log(responseJson);
                history.push('/admin/roles');
            }
        }
        );

    }


    render() {
        return (
            <div>
                <h2>::Delete role::</h2>
                <h3>Are you sure you want to delete this?</h3>
                <div>
                    <h4>Role Information</h4>
                    <dl class="row">
                        <dt class="col-sm-2">
                            Role Name:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.roleName}
                        </dd>
                    </dl>

                    <form onSubmit={this.onConfirmation}>
                        <input type="hidden" asp-for="Id" />
                        <button type="submit" class="btn btn-danger">Delete</button> |
                        <button onClick={this.onCancel} className="btn btn-primary">Back to List</button>
                    </form>
                </div>
            </div>
        )
    }
}

EditRole.js

import { Component } from "react";
import { getData, putData } from "../services/AccessAPI";

export default class EditRole extends Component {
    constructor(props) {
        super(props);
        this.state = {
            id: '',
            roleName: '',
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

    }

    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }

 
    componentDidMount() {
        const { id } = this.props.match.params;
        getData('api/Role/' + id).then(
            (result) => {
                if (result) {
                    this.setState({
                        id: result.id,
                        roleName: result.roleName,
                        loading: false
                    });
                }
            }
        );
    }

    onSubmit(e) {
        e.preventDefault();
        const { history } = this.props;
        const { id } = this.props.match.params;

        let roleObj = {
            id: this.state.id,
            roleName: this.state.roleName
        }

        putData('api/Role/Edit/' + id, roleObj).then((result) => {
            let responseJson = result;
            //console.log("update response: ");
            if (responseJson) {
                console.log(responseJson);
                history.push('/admin/roles');
            }
        }

        );
    }

    render() {
        return (
            <div className="row">
                <div className="col-md-4">
                    <h3>Edit Role</h3>
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <label className="control-label">Role Name: </label>
                            <input className="form-control" type="text" value={this.state.roleName} onChange={this.onChange} name="roleName"
                                onKeyDown={this.onKeyDown} ></input>
                        </div>

                        <div className="form-group">
                            <button onClick={this.onUpdateCancel} className="btn btn-default">Cancel</button>
                            <input type="submit" value="Edit" className="btn btn-primary"></input>
                        </div>

                    </form>

                </div>
            </div>
        );
    }
}

Roles.js

import { Component } from "react";
import { getData } from "../services/AccessAPI";

export default class Roles extends Component {
    constructor(props) {
        super(props);
        this.state = {
            roles: [],
            loading: true
        };

        this.onRoleCreate = this.onRoleCreate.bind(this);
        this.onRoleEdit = this.onRoleEdit.bind(this);
        this.onRoleDelete = this.onRoleDelete.bind(this);

    }

    onRoleCreate(){
        const { history } = this.props;
        history.push('/admin/role/create');
    }

    onRoleEdit(id){
        const {history} = this.props;
        history.push('/admin/role/edit/' + id);
    }

    onRoleDelete(id){
        const{history} = this.props;
        history.push('/admin/role/delete/' + id);
    }

    componentDidMount() {
        this.getAllRoles();
    }

    getAllRoles() {
        getData('api/Role/GetAll').then(
            (result) => {
                if (result) {
                    this.setState({
                        roles: result,
                        loading: false
                    });
                }
            }
        );
    }

    populateRolesTable(roles) {
        return (
            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>Roles</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        roles.map(role => (
                            <tr key={role.id}>
                                <td>{role.roleName}</td>
                                <td><button onClick={() => this.onRoleEdit(role.id)} className="btn btn-success">Edit</button> ||
                                    <button onClick={() => this.onRoleDelete(role.id)} className="btn btn-danger">Delete</button></td>
                            </tr>
                        ))
                    }
                </tbody>
            </table>
        );
    }

    render() {
        let contnet = this.state.loading ? (
            <p>
                <em>Loading ... </em>
            </p>

        ) : (
            this.populateRolesTable(this.state.roles)
        )
        return (
            <div>
                <h4>List of roles</h4>
                <button onClick={() => this.onRoleCreate()} className="btn btn-primary">Create new role</button>
                {contnet}
            </div>
        );
    }
}

  • Create User’s components in src->components->User

CreateUser.js

import { Component } from "react";
import SessionManager from "../Auth/SessionManager";
import { postData } from "../services/AccessAPI";

export default class CreateUser extends Component {
    constructor(props) {
        super(props);
        this.state = {
            fullName: '',
            email: '',
            userName: '',
            password: '',
            confirmationPassword: '',
            roles: [],
            loading: true
        };

        this.onSubmit = this.onSubmit.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onClickBack = this.onClickBack.bind(this);

    }

    onSubmit(e) {
        e.preventDefault();
        const { history } = this.props;

        if (this.state.password !== this.state.confirmationPassword) {
            alert("Password and confirm password are not same");
            return;
        }

        let userObj = {
            fullName: this.state.userName,
            email: this.state.email,
            userName: this.state.userName,
            password: this.state.password,
            confirmationPassword: this.state.confirmationPassword,
            roles: []
        }

        postData('api/User/Create', userObj).then((result) => {
            let responseJson = result;
            if (responseJson) {
                history.push('/admin/users');
            }
        });
    }

    onClickBack(e){
        e.preventDefault();
        const { history } = this.props;

        if(SessionManager.getToken()){
            history.push('/admin/users');
        }else{
            history.push('/login');
        }   
    }

    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }

    render() {
        return (
            <div className="row">
                <div className="col-md-4">
                    <h3>Create new user</h3>
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <label className="control-label">Full Name: </label>
                            <input className="form-control" type="text" name="fullName" value={this.state.fullName} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Email: </label>
                            <input className="form-control" type="text" name="email" value={this.state.email} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">User Name: </label>
                            <input className="form-control" type="text" name="userName" value={this.state.userName} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Password: </label>
                            <input className="form-control" type="password" name="password" value={this.state.password} onChange={this.onChange}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Confirm Password: </label>
                            <input className="form-control" type="password" name="confirmationPassword" value={this.state.confirmationPassword} onChange={this.onChange}></input>
                        </div>


                        <div className="form-group">
                            <input type="submit" value="Create User" className="btn btn-primary"></input> &nbsp; &nbsp; 
                            <input type="button" value="Back" onClick={this.onClickBack} className="btn btn-primary"></input>
                        </div>

                    </form>

                </div>
            </div>
        );
    }
}

DeleteUser.js

import React, { Component } from "react";
import { deleteData, getData } from "../services/AccessAPI";

export class DeleteUser extends Component {
    constructor(props) {
        super(props);

        this.state = {
            fullName: '',
            userName: '',
            email: '',
            roles: [],
            loading: true
        }

        this.onCancel = this.onCancel.bind(this);
        this.onConfirmation = this.onConfirmation.bind(this);
    }

    componentDidMount() {
        const { id } = this.props.match.params;

        getData('api/User/GetUserDetails/' + id).then(
            (result) => {
                console.log("Role for edit: ");
                console.log(result);
                if (result) {
                    this.setState({
                        fullName: result.fullName,
                        userName: result.userName,
                        email: result.email,
                        roles: result.roles,
                        loading: false
                    });
                }
            }
        );
    }

    onCancel() {
        const { history } = this.props;
        history.push('/admin/users');
    }

    onConfirmation(e) {
        e.preventDefault();

        const { id } = this.props.match.params;
        const { history } = this.props;

        deleteData('api/User/Delete/' + id).then((result) => {
            let responseJson = result;
            if (responseJson) {
                history.push('/admin/users');
            }
        }
        );

    }


    render() {
        return (
            <div>
                <h2>::Delete user::</h2>
                <h3>Are you sure you want to delete this?</h3>
                <div>
                    <h4>User Information</h4>
                    <dl class="row">
                        <dt class="col-sm-2">
                            Full Name:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.fullName}
                        </dd>
                    </dl>

                    <dl class="row">
                        <dt class="col-sm-2">
                            User Name:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.userName}
                        </dd>
                    </dl>

                    <dl class="row">
                        <dt class="col-sm-2">
                            Email:
                        </dt>
                        <dd class="col-sm-10">
                            {this.state.email}
                        </dd>
                    </dl>

                    <form onSubmit={this.onConfirmation}>
                        <input type="hidden" asp-for="Id" />
                        <button type="submit" class="btn btn-danger">Delete</button> |
                        <button onClick={this.onCancel} className="btn btn-primary">Back to List</button>
                    </form>
                </div>
            </div>
        )
    }
}

UpdateUser.js


import { Component } from "react";
import { getData, putData } from "../services/AccessAPI";

export default class UpdateUser extends Component{
    constructor(props){
        super(props);
        this.state = {
            id: '',
            fullName: '',
            userName: '',
            email: '',
            roles: []
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

    }

    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }

    onKeyDown = (e) => {
        if (e.key === 'Enter') {
            this.update(false);
        }
    }


    componentDidMount(){
        const {id} = this.props.match.params;
        getData('api/User/GetUserDetails/' + id).then(
            (result) => {
                //let responseJson = result;
                console.log("user for edit: ");
                console.log(result);
                if (result) {
                    this.setState({
                        //users: result,
                        id: result.id,
                        fullName: result.fullName,
                        userName: result.userName,
                        email: result.email,
                        loading: false
                    });
                }
            }
        );
    }

    onSubmit(e){
        e.preventDefault();
        const {history} = this.props;
        const {id} = this.props.match.params;

        let userProfile = {
            id: this.state.id,
            fullName: this.state.fullName,
            email: this.state.email,
            roles: this.state.roles
        }

        putData('api/User/EditUserProfile/' + id, userProfile).then((result) => {
            let responseJson = result;
            console.log("update response: ");
            
            if(responseJson){
                console.log(responseJson);
                history.push('/admin/users');
            }
        }

        );
    }

    render(){
        return(
            <div className="row">
                <div className="col-md-4">
                    <h3>Edit User</h3>
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <label className="control-label">Full Name: </label>
                            <input className="form-control" type="text" value={this.state.fullName} onChange={this.onChange} name="fullName"
                            onKeyDown={this.onKeyDown} ></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">User Name: </label>
                            <input className="form-control" type="text" value={this.state.userName} disabled = {true} readOnly = {true}></input>
                        </div>

                        <div className="form-group">
                            <label className="control-label">Email: </label>
                            <input className="form-control" type="text" value={this.state.email} onChange={this.onChange} name="email"
                            onKeyDown={this.onKeyDown}></input>
                        </div>

                        <div className="form-group">
                            <button onClick={this.onUpdateCancel} className="btn btn-default">Cancel</button>
                            <input type="submit" value="Edit" className="btn btn-primary"></input>
                        </div>

                    </form>

                </div>
            </div>
        );
    }
}

Users.js


import { Component } from "react";
import { getData } from "../services/AccessAPI";

export default class Users extends Component {
    constructor(props) {
        super(props);
        this.state = {
            users: [],
            loading: true
        };

        this.onUserCreate = this.onUserCreate.bind(this);
        this.onUserDelete = this.onUserDelete.bind(this);
    }


    componentDidMount() {
        this.getAllUsersData();
    }

    onUserCreate(){
        const{history} = this.props;
        history.push('/admin/user/create');
    }


    onUserEdit(id){
        const { history } = this.props;
        history.push('/admin/user/edit/' + id);
    }

    onUserDelete(id){
        const {history} = this.props;
        history.push('/admin/user/delete/' + id);
    }

    getAllUsersData() {
        getData('api/User/GetAll').then(
            (result) => {
                if (result) {
                    this.setState({
                        users: result,
                        loading: false
                    });
                }
            }
        );

    }

    renderAllUsersTable(users) {
        return (
            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>Full Name</th>
                        <th>User Name</th>
                        <th>Email</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        users.map(user => (
                            <tr key={user.id}>
                                <td>{user.fullName}</td>
                                <td>{user.userName}</td>
                                <td>{user.email}</td>
                                <td><button onClick={() => this.onUserEdit(user.id)} className="btn btn-success">Edit</button> ||
                                    <button onClick={() => this.onUserDelete(user.id)} className="btn btn-danger">Delete</button></td>
                            </tr>
                        ))
                    }
                </tbody>
            </table>
        );
    }

    render() {
        let content = this.state.loading ? (
            <p>
                <em>Loading...</em>
            </p>
        ) : (
            this.renderAllUsersTable(this.state.users)
        )

        return (
            <div>
                <h3>List of Users</h3>
                <button onClick={() => this.onUserCreate()} className="btn btn-primary">Create new user</button>
                {content}
            </div>
        );
    }
}

  • Create UsersRole components in src->components->UsersRoles folder

RoleList.js

const RoleList = (props) => {

    //debugger;
    const roles = props.roles;
    const userRoles = props.userRoles;


    function isExists(roleName) {
        if (userRoles.length <= 0) return false;
        return userRoles.includes(roleName);
    }

    const roleList = (
        <div>
            <ul className="checkBoxList">
                {
                    roles.map((role, index) => (

                        <li key={index}>
                            <input type="checkbox" checked={isExists(role.roleName)} value={role.roleName} onChange={props.onChange} ></input>
                            <span class="input-group-addon">&nbsp;</span>
                            <label>{role.roleName}</label>
                        </li>
                    )
                    )
                }
            </ul>
        </div>
    );

    return roleList;
}

export default RoleList;

UsersRoles.js

import { Component } from "react";
import { getData, putData } from "../services/AccessAPI";
import RoleList from "./RoleList";

export default class UsersRole extends Component {
    constructor(props) {
        super(props);
        this.state = {
            userId: '',
            fullName: '',
            userName: '',
            userRoles: [],
            roles: [],
            msg: '',
            loading: true
        };

        this.onSearch = this.onSearch.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
        this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
    }

    onSubmit(e) {
        e.preventDefault();
        let userRoles = {
            userName: this.state.userName,
            roles: this.state.userRoles
        }
        putData('api/User/EditUserRoles', userRoles).then((result) => {
            let responseJson = result;
            if (responseJson) {
                this.setState({ msg: "User's roles updated successfully!" });
            }
        }

        );
    }

    handleCheckboxChange = (event) => {

        if (event.target.checked) {
            if (!this.state.userRoles.includes(event.target.value)) {
                this.setState(prevState => ({ userRoles: [...prevState.userRoles, event.target.value] }));
            }
        } else {
            this.setState(prevState => ({ userRoles: prevState.userRoles.filter(roleName => roleName !== event.target.value) }));
        }

    }

    onChange(e) {
        this.setState({ [e.target.name]: e.target.value });
    }


    componentDidMount() {
        this.getAllRoles();
    }


    onSearch(userName) {
        getData('api/User/GetUserDetailsByUserName/' + userName).then(
            (result) => {
                if (result) {
                    this.setState({
                        userRoles: result.roles,
                        fullName: result.fullName,
                        userName: result.userName,
                        loading: false
                    });
                }
            }
        );
    }

    getAllRoles() {
        //debugger;
        getData('api/Role/GetAll').then(
            (result) => {
                if (result) {
                    this.setState({
                        roles: result,
                        loading: false
                    });
                }
            }
        );
    }


    renderRoleList() {
        return (
            <RoleList roles={this.state.roles} userRoles={this.state.userRoles} onChange={this.handleCheckboxChange} />
        );
    };


    render() {

        let renderCheckbox = this.renderRoleList();


        return (
            <div>
                <h3>Users Role</h3>
                <div className="input-group">
                    <input className="col-md-3" type="text" name="userName" placeholder="Enter user name" value={this.state.userName} onChange={this.onChange}></input>
                    <span class="input-group-addon">&nbsp;</span>
                    <button className="btn btn-primary" onClick={() => this.onSearch(this.state.userName)}>
                        Search
                    </button>
                </div>
                <label>Full Name: {this.state.fullName}</label>
                <label className="col-md-4">User Name: {this.state.userName}</label>
                <hr></hr>



                <form onSubmit={this.onSubmit}>
                    <div className="form-group">
                        {renderCheckbox}
                    </div>
                    <div className="form-group">
                        <input type="submit" value="Save" className="btn btn-primary"></input>
                    </div>
                </form>
                <label>{this.state.msg}</label>
            </div>
        );
    }
}

Step 5: Add Route in App.js

  • Modify App.js as follows
  • Here I have define route for employees, create, edit, delete

App.js

import React, { Component } from 'react';
import { Route } from 'react-router';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';

import './custom.css'


import { Customers } from './components/Customer/Customers';
import { Create } from './components/Customer/Create';
import { Edit } from './components/Customer/Edit';
import { Delete } from './components/Customer/Delete';

import Login from './components/Auth/Login';
import Logout from './components/Auth/Logout';
import Registration from './components/Auth/Registration';
import Users from './components/User/Users';
import UpdateUser from './components/User/UpdateUser';
import Roles from './components/Role/Roles';
import CreateRole from './components/Role/CreateRole';
import EditRole from './components/Role/EditRole';
import { DeleteRole } from './components/Role/DeleteRole';
import CreateUser from './components/User/CreateUser';
import { DeleteUser } from './components/User/DeleteUser';
import UsersRole from './components/UsersRoles/UsersRoles';
import SessionManager from './components/Auth/SessionManager';

export default class App extends Component {
  static displayName = App.name;


  render() {
    return (
      //if(SessionManager.getToken())
      SessionManager.getToken() ? (
        <Layout>
          <Route exact path='/home' component={Home} />

          <Route path='/logout' component={Logout} />
          <Route path='/registration' component={Registration} />


          <Route path='/banking/customers' component={Customers} />
          <Route path='/banking/customer/create' component={Create} />
          <Route path='/banking/customer/edit/:id' component={Edit}></Route>
          <Route path='/banking/customer/delete/:id' component={Delete}></Route>



          <Route path='/counter' component={Counter} />
          <Route path='/fetch-data' component={FetchData} />

          <Route path='/admin/users' component={Users}></Route>
          <Route path='/admin/user/edit/:id' component={UpdateUser}></Route>
          <Route path='/admin/user/delete/:id' component={DeleteUser}></Route>

          <Route path='/admin/roles' component={Roles}></Route>
          <Route path='/admin/role/create' component={CreateRole}></Route>
          <Route path='/admin/role/edit/:id' component={EditRole}></Route>
          <Route path='/admin/role/delete/:id' component={DeleteRole}></Route>

          <Route path='/admin/usersroles' component={UsersRole}></Route>
          <Route path='/admin/user/create' component={CreateUser}></Route>

        </Layout>

      ) : (

        <>
          <Layout>
            <Route path={'/', "/login"} component={Login} />
            <Route path='/admin/user/register' component={CreateUser}></Route>
          </Layout>
        </>

      )

    );
  }
}

Step 6: Add required menu

  • Change NavMenu.js as follows in src->components

NavMenu.js

import React, { Component } from 'react';
import {
    Collapse, Container, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink, UncontrolledDropdown,
    DropdownToggle,
    DropdownMenu,
    DropdownItem,
} from 'reactstrap';

import { Link } from 'react-router-dom';
import './NavMenu.css';
import LoginMenu from './LoginMenu';
//import { TempDropdown } from './TempDropdown';


export class NavMenu extends Component {
    static displayName = NavMenu.name;

    constructor(props) {
        super(props);

        this.toggleNavbar = this.toggleNavbar.bind(this);
        this.state = {
            collapsed: true
        };
    }

    toggleNavbar() {
        this.setState({
            collapsed: !this.state.collapsed
        });
    }

    render() {
        return (
            <header>
                <Navbar className="navbar-expand-sm navbar-toggleable-sm ng-white border-bottom box-shadow mb-3" light>
                    <Container>
                        <NavbarBrand tag={Link} to="/">Auth</NavbarBrand>
                        <NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
                        <Collapse className="d-sm-inline-flex flex-sm-row-reverse" isOpen={!this.state.collapsed} navbar>
                            <ul className="navbar-nav flex-grow">
                                <NavItem>
                                    <NavLink tag={Link} className="text-dark" to="/home">Home</NavLink>
                                </NavItem>

                                <UncontrolledDropdown nav inNavbar>
                                    <DropdownToggle nav caret>
                                        Banking
                                    </DropdownToggle>
                                    <DropdownMenu right>
                                        <DropdownItem>
                                            <NavLink tag={Link} className="text-dark" to="/banking/customers">Customer</NavLink>
                                        </DropdownItem>
                                    </DropdownMenu>
                                </UncontrolledDropdown>

                                <UncontrolledDropdown nav inNavbar>
                                    <DropdownToggle nav caret>
                                        Admin
                                    </DropdownToggle>
                                    <DropdownMenu right>
                                        <DropdownItem>
                                            <NavLink tag={Link} className="text-dark" to="/admin/users">Users</NavLink>
                                        </DropdownItem>
                                        <DropdownItem divider />
                                        <DropdownItem>
                                            <NavLink tag={Link} className="text-dark" to="/admin/roles">Roles</NavLink>
                                        </DropdownItem>

                                        <DropdownItem>
                                            <NavLink tag={Link} className="text-dark" to="/admin/usersroles">Users Roles</NavLink>
                                        </DropdownItem>


                                    </DropdownMenu>
                                </UncontrolledDropdown>

                                {/* <NavItem>
                                    <NavLink tag={Link} className='text-dark' to="/login">Login</NavLink>
                                </NavItem> */}

                                <NavItem>
                                    <NavLink tag={Link} className='text-dark' to="/logout">Logout</NavLink>
                                </NavItem>


                            </ul>
                        </Collapse>
                    </Container>
                </Navbar>
            </header>
        );
    }
}

Step 7: Run and test the application

  • Run backend asp.net core application using visual studio
  • Go to the root directory of react application and run client application using the following command
npm start -o
  • Register user first then login and try to get customers list

Download Source Code