Skip to content

Commit e5ee65b

Browse files
committed
[Api+Web] Require authentication to retrieve roles and permissions
1 parent 7851385 commit e5ee65b

File tree

2 files changed

+25
-29
lines changed

2 files changed

+25
-29
lines changed

attendance-api/routes/api.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,10 @@
5353
Route::get('reports/student-stats', [ReportController::class, 'studentStats']);
5454
Route::get('poll', [PollController::class, 'poll']);
5555

56+
Route::get('roles', fn () => collect([
57+
"roles" => Role::all()->map(fn ($role) => ['name'=>$role->name, 'permissions'=>$role->permissions->pluck("name")]),
58+
"permissions" => Permission::all()->pluck("name")
59+
]));
5660
});
5761

58-
Route::get('roles', fn () => collect([
59-
"roles" => Role::all()->map(fn ($role) => ['name'=>$role->name, 'permissions'=>$role->permissions->pluck("name")]),
60-
"permissions" => Permission::all()->pluck("name")
61-
]));
6262
Route::get('info', fn () => ['git_hash' => config('app.git_hash')]);
63-
Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,42 @@
11
import { HttpClient } from '@angular/common/http';
22
import { Injectable } from '@angular/core';
3-
import { map, Observable, of, ReplaySubject, switchMap, take } from 'rxjs';
4-
import { Permission, Role, RolesResponse } from 'src/app/models/role.model';
3+
import { map, Observable, of, shareReplay, switchMap } from 'rxjs';
4+
import { Role, RolesResponse } from 'src/app/models/role.model';
55
import { environment } from 'src/environments/environment';
66
import { AuthService } from './auth.service';
77

88
@Injectable({
99
providedIn: 'root'
1010
})
1111
export class PermissionsService {
12-
private readonly roles = new ReplaySubject<Map<string, Role>>(1);
13-
private readonly permissions = new ReplaySubject<Permission[]>(1);
12+
private readonly roles: Observable<Map<string, Role>>;
1413

1514
constructor(private httpClient: HttpClient, private authService: AuthService) {
16-
this.httpClient.get<RolesResponse>(environment.apiRoot + '/roles').subscribe(roles => {
17-
this.roles.next(new Map(roles.roles.map(role => [role.name, role])));
18-
this.permissions.next(roles.permissions);
19-
});
15+
this.roles = this.httpClient.get<RolesResponse>(environment.apiRoot + '/roles').pipe(
16+
map(rolesResponse => new Map(rolesResponse.roles.map(role => [role.name, role]))),
17+
shareReplay(1)
18+
);
2019
}
2120

2221
public getAllRoles(): Observable<Role[]> {
2322
return this.roles.pipe(map(roles => Array.from(roles.values())));
2423
}
2524

26-
public checkPermissions(permissions: string[]): Observable<boolean> {
25+
public getCurrentUserPermissions(): Observable<string[]> {
2726
return this.authService.getUser().pipe(
28-
take(1),
29-
switchMap(user => user === null ? of(false) : this.roles.pipe(map(roles =>
30-
user.role_names.reduce((prev, role) => {
31-
if (prev) {
32-
return true;
33-
}
34-
35-
if (!roles.has(role)) {
36-
return false;
37-
}
27+
switchMap(user => user === null ? of([])
28+
: this.roles.pipe(
29+
map(roles => user.role_names.flatMap(role => roles.get(role)?.permissions ?? []))
30+
)
31+
)
32+
);
33+
}
3834

39-
const role_permissions = roles.get(role)!!.permissions;
40-
return permissions.reduce((prev, permission) => prev && role_permissions.includes(permission), true);
41-
}, false)
42-
))
43-
));
35+
public checkPermissions(neededPermissions: string[]): Observable<boolean> {
36+
return this.getCurrentUserPermissions().pipe(
37+
map(userPermissions => {
38+
return neededPermissions.reduce((allowed, neededPermission) => allowed && userPermissions.includes(neededPermission), true);
39+
})
40+
);
4441
}
4542
}

0 commit comments

Comments
 (0)