What is the role-based menu item feature and routing in Angular 14?

My Angular App is running version 14. The header contains links for Register, Login, Add New Employee, List of Employees, Update Employee Profile, Employee Profile, Working Hours, and Logout.

https://i.sstatic.net/M1len.png

If a user with an Admin role logs into the site, they should see the following menu items:

  1. Login
  2. Register
  3. Add New Employees
  4. Update Employee Profile
  5. List of employees
  6. Logout

If a user with an employee role logs in, they should see the following menu items:

  1. Login
  2. Employee Profile
  3. Working Hours
  4. Logout

For users with a support role, the header should display these menu items:

  1. Login
  2. List of Employees
  3. Logout

I'm looking to implement a role-based menu. Can someone assist me with this?

Below is my app.component.html code:

<div>
  <nav class="navbar navbar-expand navbar-dark bg-dark">
    <a href="#" class="navbar-brand">Dashboard</a>
    <div class="navbar-nav mr-auto">
      <li class="nav-item">
        <a routerLink="register" class="nav-link">Register</a>
      </li>
      <li class="nav-item">
        <a routerLink="login" class="nav-link">Login</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">Add New Employee</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">List of Employees</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">Update Employee Profile</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">Employee Profile</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">Working Hours</a>
      </li>
      <li class="nav-item">
        <a routerLink="" class="nav-link">Logout</a>
      </li>
    </div>
  </nav>

  <div class="container mt-3">
    <router-outlet></router-outlet>
  </div>
</div>

Here's a link to my app.component.ts file: https://i.sstatic.net/FugCn.png

Folder structure visualized here: https://i.sstatic.net/F3yj1.png

The login-user.component.ts file looks like this:

import { Component } from '@angular/core';
import { User } from 'src/app/models/user.model';
import { UserService } from 'src/app/services/user.service';

@Component({
  selector: 'app-login-user',
  templateUrl: './login-user.component.html',
  styleUrls: ['./login-user.component.css']
})
export class LoginUserComponent {

  user: User = {
    username: '',
    password:''
  };
  submitted = false;

  constructor(private userService: UserService) { }

  loginUser(): void {
    const data = {
      username: this.user.username,
      password:this.user.password
    };

    this.userService.login(data)
      .subscribe({
        next: (res) => {
          console.log(res);
          this.submitted = true;
        },
        error: (e) => console.error(e)
      });
  }

  newUser(): void {
    this.submitted = false;
    this.user = {
      username: '',
      password:''
    };
  }

}

enter code here

Here's a snippet from my user.service.ts file:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../models/user.model';

const baseUrl = 'http://localhost:8080/api/user';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  constructor(private http: HttpClient) { }

  signup(data: any): Observable<any> {
    return this.http.post(baseUrl+"/signup", data);
  }

  login(data: any): Observable<any> {
    return this.http.post(baseUrl+"/login", data);
  }

  getAll(): Observable<User[]> {
    return this.http.get<User[]>(baseUrl);
  }

  ...

}

And finally, my app-routing.module.ts setup:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
...

To learn more about implementing a role-based menu in Angular 14, check out this helpful thread on Stack Overflow: Angular Role Based Menu And Page Routing

Answer №1

Great question! Setting up authorization is a complex task that involves work across multiple layers of an application.

For a basic solution in an Angular app (or any other single page application technology), you can follow these steps:

1. Create a service that handles the validation of user credentials entered on the UI. Here's an example service I've created for a proof of concept:

// Code example here

2. Set up a front-end storage system to store current user data, such as user properties, permissions, tokens, etc.

// Code example here

3. Develop a front-end component, typically a form, that interacts with the back-end through the service created earlier and saves user data in the storage.

// Code example here

4. Utilize the auth-storage service to check the current user information whenever needed throughout your application.

// Code example here

This implementation is very lightweight and not production-ready. It demonstrates how to log in a user, persist user data, and utilize this data in various parts of the application.

Additional components that may be missing include implementing route guards to protect Angular routes, using HTTP interceptors for unauthorized responses, and encapsulating permission checking code in structural directives.

Overall, proper implementation of authorization in an application requires thorough research and customization based on specific requirements.

Answer №2

Displaying menus from the client side is not the recommended approach. It is advisable to fetch the menu data from the server side.

If you are required to proceed with this method, consider creating an array and loop through it while checking for roles.

Answer №3

To implement a role-based menu, create a separate component for each user role and use nested conditional statements to direct users to the appropriate component based on their role during login. Additionally, utilize role guards for added security measures. A sample code snippet is provided below:

 if (this.currentUserDetails.roles == "ADMIN") {
      this.router.navigate(["/admin",])
      this.toastr.success('You Have Successfully Logged In', username);
    }
    else

      if (this.currentUserDetails.roles == "EMPLOYEE") {
        this.router.navigate(["/employee",])
        this.toastr.success('You Have Successfully Logged In', username);
      }
      else

        if (this.currentUserDetails.roles == "SUPPORT") {
          this.router.navigate(["/support",])
          this.toastr.success('You Have Successfully Logged In', username);
        }
  },

A JWT token is used to store user roles. The role guard function presented here is designed to validate user access based on their assigned role.

checkUserLogin(route: ActivatedRouteSnapshot, url: any): boolean {
if (this.tokenStorageService.isUserLoggedIn()) {
  const userRole = this.tokenStorageService.getRole();
  if (route.data['role'] && route.data['role'].indexOf(userRole) === -1) {
    this.router.navigate(['/home']);
    window.alert("You don't have permission to view this page")
    return false;
  }
  return true;
}
return true;

}

In your app-routing.module.ts file, add the following configuration to each component that requires specific role access:

canActivate: [RoleGuard],
    data: {
      role: 'ADMIN'
    },

Define an enum with roles mentioned in the above code snippet and import it into app-routing.module.ts:

export enum Role {
ADMIN = 'ADMIN',
EMPLOYEE = 'EMPLOYEE',
SUPPORT = 'SUPPORT',
}

Answer №4

One way to manage user permissions is by storing them in the database alongside user information. This allows you to retrieve the permissions when a user logs in and check if they have access to certain menu items based on their roles. By setting up guards, you can protect routes from unauthorized users and ensure that only those with the correct permissions can access sensitive areas of your application.

Answer №5

When implementing multiple security levels, my suggestion would be to utilize GUARDS and establish routing accordingly

The CanActivate interface should be used with the following signature: canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Separate an array in TypeScript based on the sign of each number, and then replace the empty spaces with null objects

Hey, I'm facing a little issue, I have an Array of objects and my goal is to split them based on the sign of numbers. The objects should then be dynamically stored in different Arrays while retaining their index and getting padded with zeros at the b ...

Is casting performed by <ClassName> in typescript?

According to the Angular DI documentation, there is an example provided: let mockService = <HeroService> {getHeroes: () => expectedHeroes } So, my question is - can we consider mockService as an instance of HeroService at this point? To provide ...

How can you inform TypeScript about a file that will be included using a script tag?

I am currently utilizing TypeScript for my front-end JavaScript development, and I have a situation where I am loading two scripts from my index.html file as shown below: <script src="replacements.js"></script> <script src="socket.js">&l ...

Attempting to create a finalized build of Express using Typescript

Encountering the following error message when executing this command: npm run clear && tsc -P ./tsconfig.app.json && npm run post:build or tsc -p . Node version: v12.13.0 NPM: v6.14.2 Express: 4 Has anyone else faced a similar issue? > ...

What is the process for updating npm and node version on Windows operating system?

Currently immersed in a finance project, but embarking on a new one where we are facing a node version issue. Any tips on how to avoid this problem? ...

Is it necessary to strictly adhere to NPM versions in AngularCLI?

Can AngularCli be configured to create a package.json file with strict versioning? Instead of using the caret symbol (^) like this: "@angular/common": "^6.0.3", "@angular/compiler": "^6.0.3", "@angular/core": "^6.0.3", It should be like this: "@angula ...

What steps are involved in building a modal pop-up in Angular without using any pre-existing libraries

I am looking to create a modal popup when a button is clicked. I want to achieve this without relying on any additional dependencies. The method I have used below successfully creates a fully functional modal, but I am unsure if this is the best way to do ...

Changing the font family for a single element in Next.js

One unique aspect of my project is its global font, however there is one element that randomly pulls font families from a hosted URL. For example: https://*****.com/file/fonts/Parnian.ttf My page operates as a client-side rendered application (CSR). So, ...

Utilize ngx-filter-pipe to Streamline Filtering of Multiple Values

Need assistance with filtering an array using ngx-filter-pipe. I have managed to filter based on a single value condition, but I am unsure how to filter based on multiple values in an array. Any guidance would be appreciated. Angular <input type="text ...

Guide on showing a component exclusively for iPads with React and TypeScript

I need help displaying an icon only in the component for iPad devices, and not on other devices. As a beginner in coding for iPads and mobile devices, I am unsure how to achieve this specific requirement for the iPad device. Below is the code snippet tha ...

What is the best way to implement custom sorting for API response data in a mat-table?

I have been experimenting with implementing custom sorting in a mat-table using API response data. Unfortunately, I have not been able to achieve the desired result. Take a look at my Stackblitz Demo https://i.sstatic.net/UzK3p.png I attempted to implem ...

What is the best way to conduct tests on Typescript modules that are not intended for

Even though the compiler accepts my current solution without any errors, the tests are still failing with the message "ReferenceError: myFunction is not defined". I am interested in testing the functionality of the following module using TypeScript: File1 ...

Displaying centered text over a mat-progress-spinner using Angular, Material, and Flex-Layout

In my Angular project, I am utilizing material and flex-layout. One challenge I encountered is centering text inside a mat-progress-spinner element. I attempted to achieve this by using position absolute, but the issue is that it doesn't stay centered ...

What is the best way to extract and connect data from a JSON file to a dropdown menu in Angular 2+?

Here is an example of my JSON data: { "Stations": { "44": { "NAME": "Station 1", "BRANCH_CD": "3", "BRANCH": "Bay Branch" }, "137": { "NAME": "Station 2", ...

Creating a mat-grid-list using Angular Material involves adding the necessary dependencies and components

I am encountering an issue while attempting to set up a mat-grid-list with Angular Material. Unfortunately, nothing is displaying on my page. Here is the component info-section : <div class="mat-grid-list" cols="4" rowHeight="1 ...

Angular view not showing dates retrieved from MySQL database

Currently, I am experimenting with Angularjs alongside TypeScript to create a simple to-do list as a web page for practice and fun. Below is my controller that interacts with the database and stores the objects: module app.ToDo { class ToDoCtrl { ...

Exporting the interface for the state of the redux store

After setting up a redux module, I have organized the following files: //state.tsx export default interface State { readonly user: any; readonly isLoggedIn: boolean; } //types.tsx export default { REQUEST: 'authentication/REQUEST', SUC ...

Exploring the Benefits of Angular 2 Beta Typings within Visual Studio (ASP.NET 4)

During my initial experiences with Angular 2.0 alpha versions, I utilized the files from DefinitelyTyped to incorporate typings for TypeScript in Visual Studio. The process was straightforward - simply adding the d.ts files to the project. However, as we t ...

Utilizing MSAL's loginRedirect within an Ngrx Effect: A step-by-step guide

Is there a way to utilize Msal angular's loginRedirect(): void function instead of loginPopup(): Promise in an Ngrx Effect? I've been able to successfully implement the loginPopup() method, but since loginRedirect() has a void return type, it di ...

Using React to iterate through the child components of the parent

I have created a component that can accept either a single child or multiple children. Here is an example with multiple children: <SideDataGridItem> <div id='top'> <div>A1</div> <div>B1</div> ...