feature: authorization - add role guard and protect products route
This commit is contained in:
parent
617053c0ee
commit
8b1b831ea2
@ -1,6 +1,7 @@
|
||||
import { Routes } from "@angular/router";
|
||||
import { Home } from "./features/home/home";
|
||||
import { authGuard } from "./core/guards/auth-guard";
|
||||
import { roleGuard } from "./core/guards/role-guard";
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@ -16,6 +17,7 @@ export const routes: Routes = [
|
||||
path: "products",
|
||||
loadChildren: () =>
|
||||
import("./features/product/product.routes").then((routes) => routes.productRoutes),
|
||||
// canActivate: [authGuard]
|
||||
canActivate: [authGuard, roleGuard],
|
||||
data: { roles: ["broker"] },
|
||||
},
|
||||
];
|
||||
|
||||
17
src/app/core/guards/role-guard.spec.ts
Normal file
17
src/app/core/guards/role-guard.spec.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { CanActivateFn } from "@angular/router";
|
||||
|
||||
import { roleGuard } from "./role-guard";
|
||||
|
||||
describe("roleGuard", () => {
|
||||
const executeGuard: CanActivateFn = (...guardParameters) =>
|
||||
TestBed.runInInjectionContext(() => roleGuard(...guardParameters));
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
});
|
||||
|
||||
it("should be created", () => {
|
||||
expect(executeGuard).toBeTruthy();
|
||||
});
|
||||
});
|
||||
12
src/app/core/guards/role-guard.ts
Normal file
12
src/app/core/guards/role-guard.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { CanActivateFn } from "@angular/router";
|
||||
import { inject } from "@angular/core";
|
||||
import { AuthService } from "../../features/auth/services/auth-service";
|
||||
|
||||
export const roleGuard: CanActivateFn = (route, state) => {
|
||||
const authService = inject(AuthService);
|
||||
|
||||
// get role from route data passed in route config.
|
||||
const roles = route.data["roles"] as string[];
|
||||
|
||||
return roles && authService.hasRoles(roles);
|
||||
};
|
||||
@ -13,4 +13,5 @@ export interface User {
|
||||
email: string;
|
||||
mobileNumber: string;
|
||||
city: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ export class AuthService {
|
||||
// User states
|
||||
readonly authState: WritableSignal<AuthState>;
|
||||
readonly user: WritableSignal<User | null>;
|
||||
readonly userRole: Signal<string | null>;
|
||||
|
||||
// Computed state for easy checking
|
||||
readonly isAuthenticated: Signal<boolean>;
|
||||
@ -45,6 +46,7 @@ export class AuthService {
|
||||
);
|
||||
this.user = signal<User | null>(cachedUser);
|
||||
this.isAuthenticated = computed(() => !!this.user());
|
||||
this.userRole = computed(() => this.user()?.role || null);
|
||||
}
|
||||
|
||||
register(userRequest: RegisterUserRequest) {
|
||||
@ -74,6 +76,16 @@ export class AuthService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user has the role.
|
||||
* Mostly used in role guard.
|
||||
*/
|
||||
hasRoles(roles: string[]) {
|
||||
const role = this.userRole();
|
||||
if (!role) return false;
|
||||
return roles.includes(role);
|
||||
}
|
||||
|
||||
logout() {
|
||||
return this.http.post(`${this.backendURL}/logout`, {}).pipe(
|
||||
tap({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user