In today’s digital landscape, managing user roles and permissions in your application has become crucial for ensuring security and personalized user experiences. If you’re developing with Ionic and Angular, this tutorial will guide you through handling user roles effectively. By the end of this article, you’ll be equipped with the knowledge to implement guards and directives that will restrict access to specific pages and control user interaction with various elements based on their roles.
Understanding User Roles and Permissions
Before we dive into the code, let’s clarify what we mean by user roles and permissions:
- User Roles: Think of roles as broad categories that define what kind of actions a user can perform in the application. Common roles include Admin, User, and Guest.
- Permissions: Permissions are specific actions that users can take within their roles (e.g., read, write, delete). A user can have one or more permissions linked to their role.
With this understanding, let’s create an example Ionic application focusing on user roles and permissions.
Setting Up the Ionic Application
- Start a New Ionic Project: Begin by creating a blank Ionic application. You can do this using the following command:
ionic start roleManagementApp blank
- Create Necessary Pages: We will need at least two pages—the Login page and a Secret Admin page. The admin will be able to access this page, while regular users will not.
ionic generate page login
ionic generate page admin
- Set Up Authentication Service: This service will handle user authentication states, including logging in and logging out, and it will maintain a record of the current user’s role and permissions.
Creating the Authentication Service
Here’s a breakdown of the key elements in our authentication service:
- Use a BehaviorSubject to maintain the current user’s authentication state.
- Store user data, including their role and permissions, in local storage using Capacitor.
- Provide methods for logging in and out.
Code Example
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { Plugins } from '@capacitor/core';
const { Storage } = Plugins;
@Injectable({ providedIn: 'root' })
export class AuthService {
private currentUser: BehaviorSubject<any> = new BehaviorSubject(null);
constructor() {
this.loadUser();
}
private async loadUser() {
const { value } = await Storage.get({ key: 'user' });
this.currentUser.next(JSON.parse(value));
}
login(userName: string): Observable<any> {
const user = userName === 'admin' ? { name: 'Admin', role: 'admin', permissions: ['read', 'write'] } :
{ name: 'User', role: 'user', permissions: ['read'] };
Storage.set({ key: 'user', value: JSON.stringify(user) });
this.currentUser.next(user);
return of(user);
}
logout() {
Storage.remove({ key: 'user' });
this.currentUser.next(null);
}
getCurrentUser(): Observable<any> {
return this.currentUser.asObservable();
}
}
Implementing Guards for Page Protection
Now that we have our authentication service set up, we can implement guards that will control access to certain routes based on user roles.
Creating a Role Guard
- Generate the Guard: Use the Angular CLI to generate a guard that will check user permissions.
ng generate guard guards/role
- Implement the Guard Logic: The guard will check the user’s role before allowing access to the admin page.
Code Example
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class RoleGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
return this.authService.getCurrentUser().pipe(
map(user => {
const expectedRole = next.data.expectedRole;
if (user && user.role === expectedRole) {
return true;
}
this.router.navigate(['login']);
return false;
})
);
}
}
- Add Guard to Routing Module: Finally, use the RoleGuard in your App Routing Module where you define the routes.
Example Routes
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'admin', component: AdminComponent, canActivate: [RoleGuard], data: { expectedRole: 'admin' } },
{ path: '', redirectTo: 'login', pathMatch: 'full' },
];
Creating Directives for Element Control
In addition to controlling access to routes, you might also want to show or hide UI elements based on user roles and permissions. For this, we will create directives.
Creating a Permission Directive
- Generate the Directive:
ng generate directive directives/hasPermission
- Implement the Directive Logic: The directive will check user permissions and hide or show the element accordingly.
Code Example
import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
import { AuthService } from '../auth.service';
@Directive({ selector: '[appHasPermission]' })
export class HasPermissionDirective implements OnInit {
@Input('appHasPermission') permissions: string[];
constructor(private authService: AuthService, private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}
ngOnInit() {
this.authService.getCurrentUser().subscribe(user => {
if (user && user.permissions.some(perm => this.permissions.includes(perm))) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
});
}
}
- Use the Directive in Your Component:
Now, you can use theappHasPermission
directive in your templates.
Example Usage
<button *appHasPermission="['write']">Only Admins can Edit</button>
Conclusion
With these implementations, you now have a robust framework for managing user roles and permissions in your Ionic application. The combination of guards and directives provides a flexible way to ensure that users can only access the functionality they are permitted to.
Through this tutorial, you learned how to set up an authentication service, implement role-based routing guards, and create directives for controlling UI element visibility based on user permissions. This framework not only enhances the security of your application but also delivers a tailored user experience.
To explore more about Ionic development, check out various resources and courses on Ionic Academy and dive deeper into enhancing your web applications.
Feel empowered to apply these concepts to your projects and see the difference it makes! Happy coding!