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:
- User enters credentials on the login page
- The application sends a request to the authentication server
- Upon successful authentication, the server returns a JWT token and user information
- The application stores the token and user information in local storage
- The token is included in subsequent API requests via an HTTP interceptor
- Protected routes check for a valid token before allowing access
- 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):
- SA (Super Admin): Has access to everything
- Admin: Has access to admin, editor, user, and guest routes
- Editor: Has access to editor, user, and guest routes
- User: Has access to user and guest routes
- 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: