Egret Admin Dashboard

Egret Documentation

Authentication & Access Control
Authentication Overview

Egret Angular implements a JWT (JSON Web Token) based authentication system. This provides a secure way to authenticate users and protect routes in your application. The authentication system is pre-configured and ready to use in your Egret Angular application.

Authentication Features

Egret's authentication system includes the following features:

  • JWT Authentication: Secure token-based authentication
  • Route Protection: Guards to protect routes from unauthorized access
  • Role-Based Access Control: Different access levels based on user roles
  • Persistent Sessions: User sessions are maintained across page refreshes
  • Redirect After Login: Users are redirected to their intended destination after login
Video Introduction
Authentication Flow

The authentication flow in Egret Angular follows these steps:

  1. User enters credentials on the login page
  2. The application sends a request to the authentication server
  3. Upon successful authentication, the server returns a JWT token and user information
  4. The application stores the token and user information in local storage
  5. The token is included in subsequent API requests via an HTTP interceptor
  6. Protected routes check for a valid token before allowing access
  7. When the user logs out, the token is removed from local storage
Authentication Service

The JwtAuthService in src/app/shared/services/auth/jwt-auth.service.ts handles all authentication-related functionality:

// Key methods in JwtAuthService
import { Injectable } from "@angular/core";
import { LocalStoreService } from "../local-store.service";
import { HttpClient } from "@angular/common/http";
import { Router, ActivatedRoute } from "@angular/router";
import { User } from "../../models/user.model";
import { BehaviorSubject } from "rxjs";

@Injectable({
  providedIn: "root",
})
export class JwtAuthService {
  // Authentication methods
  public signin(username, password) {
    // Handles user login and stores JWT token
  }

  public checkTokenIsValid() {
    // Verifies if the current token is valid
  }

  public signout() {
    // Handles user logout
  }

  isLoggedIn(): Boolean {
    // Checks if user is currently logged in
  }

  getJwtToken() {
    // Retrieves JWT token from storage
  }

  getUser() {
    // Retrieves user information from storage
  }

  setUserAndToken(token: String, user: User, isAuthenticated: Boolean) {
    // Stores user and token information
  }
}
Key Authentication Methods
  • signin(username, password): Authenticates a user with the provided credentials
  • signout(): Logs out the current user and redirects to the login page
  • isLoggedIn(): Checks if a user is currently logged in
  • checkTokenIsValid(): Verifies if the current token is still valid
  • getUser(): Retrieves the current user information
Route Protection with Guards

Egret Angular uses Angular route guards to protect routes from unauthorized access. Two main guards are provided:

AuthGuard

The AuthGuard in src/app/shared/guards/auth.guard.ts protects routes from unauthenticated users:

import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";
import { JwtAuthService } from "../services/auth/jwt-auth.service";

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router, private jwtAuth: JwtAuthService) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (this.jwtAuth.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(["/sessions/signin"], {
        queryParams: {
          return: state.url
        }
      });
      return false;
    }
  }
}
UserRoleGuard

The UserRoleGuard in src/app/shared/guards/user-role.guard.ts restricts access based on user roles:

import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";
import { JwtAuthService } from "../services/auth/jwt-auth.service";
import { MatSnackBar } from "@angular/material/snack-bar";

@Injectable()
export class UserRoleGuard implements CanActivate {
  constructor(
    private router: Router, 
    private jwtAuth: JwtAuthService, 
    private snack: MatSnackBar
  ) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    var user = this.jwtAuth.getUser();

    if (
      user &&
      route.data &&
      route.data.roles &&
      route.data.roles.includes(user.role)
    ) {
      return true;
    } else {
      this.snack.open('You do not have access to this page!', 'OK');
      return false;
    }
  }
}
Implementing Route Protection

To protect routes in your application, you can use the guards in your routing configuration:

Using AuthGuard

To protect routes from unauthenticated users, add the AuthGuard to the canActivate property:

// In app.routing.ts
{
  path: '',
  component: AdminLayoutComponent,
  canActivate: [AuthGuard], // Requires authentication
  children: [
    {
      path: 'dashboard',
      loadChildren: () => import('./views/dashboard/dashboard.module').then(m => m.DashboardModule),
      data: { title: 'Dashboard', breadcrumb: 'DASHBOARD'}
    },
    // Other routes...
  ]
}
Using UserRoleGuard

To restrict access based on user roles, add the UserRoleGuard to the canActivate property and specify the required roles in the data property:

// In dashboard.routing.ts
{
  path: 'learning-management',
  component: LearningManagementComponent,
  canActivate: [UserRoleGuard],
  data: { 
    title: 'Learning management', 
    breadcrumb: 'Learning management', 
    role: config.authRoles.user // Only users with 'user' role or higher can access
  }
}
Role-Based Access Control

Egret Angular implements a hierarchical role-based access control system. Roles are defined in src/config.ts:

// In config.ts
export const config = {
  apiUrl: 'http://ui-lib-demo-api.herokuapp.com',
  authRoles: {
    sa: ['SA'], // Only Super Admin has access
    admin: ['SA', 'Admin'], // Only SA & Admin has access
    editor: ['SA', 'Admin', 'Editor'], // Only SA & Admin & Editor has access
    user: ['SA', 'Admin', 'Editor', 'User'], // Only SA & Admin & Editor & User has access
    guest: ['SA', 'Admin', 'Editor', 'User', 'Guest'] // Everyone has access
  }
}
Role Hierarchy

The role hierarchy in Egret Angular is as follows (from highest to lowest):

  1. SA (Super Admin): Has access to everything
  2. Admin: Has access to admin, editor, user, and guest routes
  3. Editor: Has access to editor, user, and guest routes
  4. User: Has access to user and guest routes
  5. Guest: Has access only to guest routes
Using Roles in Routes

To restrict a route to specific roles, use the role property in the route data:

// Examples of role-based route protection
{
  path: 'admin-dashboard',
  component: AdminDashboardComponent,
  canActivate: [UserRoleGuard],
  data: { title: 'Admin Dashboard', role: config.authRoles.admin } // Only admins and super admins
},
{
  path: 'user-profile',
  component: UserProfileComponent,
  canActivate: [UserRoleGuard],
  data: { title: 'User Profile', role: config.authRoles.user } // All authenticated users
}
Conditional Rendering Based on Roles

You can conditionally render UI elements based on the user's role:

<!-- In your component template -->
<button mat-button *ngIf="isAdmin()">Admin Action</button>
<button mat-button *ngIf="isEditor()">Editor Action</button>
// In your component
import { JwtAuthService } from 'app/shared/services/auth/jwt-auth.service';
import { config } from 'config';

export class MyComponent {
  constructor(private jwtAuth: JwtAuthService) {}

  isAdmin() {
    const user = this.jwtAuth.getUser();
    return user && config.authRoles.admin.includes(user.role);
  }

  isEditor() {
    const user = this.jwtAuth.getUser();
    return user && config.authRoles.editor.includes(user.role);
  }
}
Authentication Pages

Egret Angular includes pre-built authentication pages:

Available Authentication Pages
  • Sign In: /sessions/signin
  • Sign Up: /sessions/signup
  • Forgot Password: /sessions/forgot-password
  • Reset Password: /sessions/reset-password
  • 404 Page: /sessions/404
  • Error Page: /sessions/error
Customizing Authentication Pages

You can customize the authentication pages by modifying the components in src/app/views/sessions/.

Integrating with Backend

Egret Angular is pre-configured to work with a JWT-based authentication backend. To integrate with your own backend:

Modifying the Authentication Service

Update the signin and checkTokenIsValid methods in JwtAuthService:

// Replace the demo authentication with your API calls
public signin(username, password) {
  this.signingIn = true;
  return this.http.post(`${environment.apiURL}/auth/login`, { username, password })
    .pipe(
      map((res: any) => {
        this.setUserAndToken(res.token, res.user, !!res);
        this.signingIn = false;
        return res;
      }),
      catchError((error) => {
        return throwError(error);
      })
    );
}

public checkTokenIsValid() {
  return this.http.get(`${environment.apiURL}/auth/profile`)
    .pipe(
      map((profile: User) => {
        this.setUserAndToken(this.getJwtToken(), profile, true);
        return profile;
      }),
      catchError((error) => {
        this.signout();
        return of(error);
      })
    );
}
HTTP Interceptor for JWT

Egret Angular includes an HTTP interceptor that automatically adds the JWT token to all API requests. The interceptor is defined in src/app/shared/interceptors/token.interceptor.ts.

Best Practices

Follow these best practices for authentication and access control in your Egret Angular application:

Authentication Guidelines
  • Always use HTTPS in production to protect authentication credentials
  • Implement token expiration and refresh mechanisms
  • Store sensitive user information only on the server, not in the JWT payload
  • Use both client-side and server-side validation for authentication
  • Implement proper error handling for authentication failures
  • Consider implementing two-factor authentication for sensitive applications
  • Always validate user permissions on the server side, not just in the client
Additional Resources

For more information on authentication and access control in Angular applications: