| @@ -2925,9 +2925,15 @@ components: | |||
| AuthResponse: | |||
| type: object | |||
| properties: | |||
| user: | |||
| $ref: '#/components/schemas/User.jsonld' | |||
| readOnly: true | |||
| '@id': | |||
| type: string | |||
| example: /api/users/1 | |||
| dbId: | |||
| type: integer | |||
| example: 1 | |||
| token: | |||
| type: string | |||
| example: JWT_TOKEN | |||
| responses: { } | |||
| parameters: { } | |||
| examples: { } | |||
| @@ -197,5 +197,6 @@ export const credentialsForm = new FormGroup({ | |||
| }); | |||
| export const authResponseForm = new FormGroup({ | |||
| user: new FormControl(null, []) | |||
| dbId: new FormControl(null, []), | |||
| token: new FormControl(null, []) | |||
| }); | |||
| @@ -1,24 +1,32 @@ | |||
| import { Injectable } from '@angular/core'; | |||
| import { Router } from '@angular/router'; | |||
| import { HttpClient } from '@angular/common/http'; | |||
| import { BehaviorSubject, Observable } from 'rxjs'; | |||
| import { BehaviorSubject, Observable, switchMap } from 'rxjs'; | |||
| import { map } from 'rxjs/operators'; | |||
| import {AuthService, UserJsonld} from "@app/core/api/v1"; | |||
| import { AuthService, UserJsonld, UserService } from "@app/core/api/v1"; | |||
| @Injectable({ providedIn: 'root' }) | |||
| export class AccountService { | |||
| private userSubject: BehaviorSubject<UserJsonld | null>; | |||
| public user: Observable<UserJsonld | null>; | |||
| constructor( | |||
| private router: Router, | |||
| private http: HttpClient, | |||
| private authService: AuthService | |||
| private authService: AuthService, | |||
| private userService: UserService, | |||
| ) { | |||
| this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user')!)); | |||
| let userData = null; | |||
| const storedUser = localStorage.getItem('user'); | |||
| if (storedUser) { | |||
| try { | |||
| userData = JSON.parse(storedUser); | |||
| } catch (error) { | |||
| localStorage.removeItem('user'); | |||
| } | |||
| } | |||
| this.userSubject = new BehaviorSubject(userData); | |||
| this.user = this.userSubject.asObservable(); | |||
| } | |||
| @@ -28,16 +36,25 @@ export class AccountService { | |||
| login(email: string, password: string) { | |||
| return this.authService.postCredentialsItem({ email, password }) | |||
| .pipe(map(response => { | |||
| localStorage.setItem('user', JSON.stringify(response.user)); | |||
| this.userSubject.next(response.user || null); | |||
| return response.user; | |||
| })); | |||
| .pipe( | |||
| switchMap(response => { | |||
| localStorage.setItem('token', response.token!); | |||
| this.userService.configuration.credentials = { 'JWT': () => response.token }; | |||
| return this.userService.usersIdGet(response.dbId!.toString()).pipe( | |||
| map(user => { | |||
| const userWithToken = { ...user, token: response.token }; | |||
| localStorage.setItem('user', JSON.stringify(userWithToken)); | |||
| this.userSubject.next(userWithToken); | |||
| return userWithToken; | |||
| }) | |||
| ); | |||
| }) | |||
| ); | |||
| } | |||
| logout() { | |||
| // remove user from local storage and set current user to null | |||
| localStorage.removeItem('user'); | |||
| localStorage.removeItem('token'); | |||
| this.userSubject.next(null); | |||
| this.router.navigate(['/account/login']); | |||
| } | |||
| @@ -46,17 +63,11 @@ export class AccountService { | |||
| return this.userValue !== null; | |||
| } | |||
| isUserAdmin(): boolean { | |||
| if (this.userValue && this.userValue?.roles) { | |||
| return this.userValue?.roles?.includes('ROLE_ADMIN'); | |||
| } | |||
| return false; | |||
| isUserAdmin(): boolean { | |||
| return this.userValue?.roles?.includes('ROLE_ADMIN') ?? false; | |||
| } | |||
| userHasRole(role: string): boolean { | |||
| if (this.userValue && this.userValue?.roles) { | |||
| return this.userValue?.roles?.includes(role); | |||
| } | |||
| return false; | |||
| return this.userValue?.roles?.includes(role) ?? false; | |||
| } | |||
| } | |||
| } | |||
| @@ -67,7 +67,10 @@ registerLocaleData(localeDe, 'de-DE'); | |||
| export function apiConfigFactory(): Configuration { | |||
| const params: ConfigurationParameters = { | |||
| basePath: environment.basePath, | |||
| withCredentials: false | |||
| withCredentials: false, | |||
| credentials: { | |||
| 'JWT': () => localStorage.getItem('token') || undefined | |||
| } | |||
| }; | |||
| return new Configuration(params); | |||
| } | |||
| @@ -1,4 +1,5 @@ | |||
| .gitignore | |||
| .openapi-generator-ignore | |||
| README.md | |||
| api.module.ts | |||
| api/api.ts | |||
| @@ -9,10 +9,11 @@ | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { UserJsonld } from './userJsonld'; | |||
| export interface AuthResponse { | |||
| readonly user?: UserJsonld; | |||
| id?: string; | |||
| dbId?: number; | |||
| token?: string; | |||
| } | |||
| @@ -1,35 +0,0 @@ | |||
| /** | |||
| * Imaq Platform | |||
| * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) | |||
| * | |||
| * The version of the OpenAPI document: 1.0.0 | |||
| * | |||
| * | |||
| * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { LocationJsonldContext } from './locationJsonldContext'; | |||
| export interface AuthResponseUser { | |||
| context?: LocationJsonldContext; | |||
| readonly id?: any | null; | |||
| readonly type?: any | null; | |||
| readonly dbId?: any | null; | |||
| email: any | null; | |||
| firstName: any | null; | |||
| lastName: any | null; | |||
| image?: any | null; | |||
| readonly imageUrl?: any | null; | |||
| readonly fullName?: any | null; | |||
| /** | |||
| * The plaintext password when being set or changed. | |||
| */ | |||
| password?: any | null; | |||
| active?: any | null; | |||
| roles?: any | null; | |||
| readonly token?: any | null; | |||
| readonly createdAt?: any | null; | |||
| } | |||
| @@ -97,9 +97,6 @@ class UserApi | |||
| #[ApiProperty(writable: false)] | |||
| public array $roles = []; | |||
| #[ApiProperty(writable: false)] | |||
| public ?string $token = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?\DateTimeImmutable $createdAt = null; | |||
| @@ -38,10 +38,18 @@ final class AuthDecorator implements OpenApiFactoryInterface | |||
| $schemas['AuthResponse'] = new \ArrayObject([ | |||
| 'type' => 'object', | |||
| 'properties' => [ | |||
| 'user' => [ | |||
| '$ref' => '#/components/schemas/User.jsonld', | |||
| 'readOnly' => true, | |||
| ] | |||
| '@id' => [ | |||
| 'type' => 'string', | |||
| 'example' => '/api/users/1', | |||
| ], | |||
| 'dbId' => [ | |||
| 'type' => 'integer', | |||
| 'example' => 1, | |||
| ], | |||
| 'token' => [ | |||
| 'type' => 'string', | |||
| 'example' => 'JWT_TOKEN', | |||
| ], | |||
| ] | |||
| ]); | |||
| @@ -28,41 +28,19 @@ use Symfonycasts\MicroMapper\MicroMapperInterface; | |||
| class JwtAuthenticator extends AbstractAuthenticator | |||
| { | |||
| public function __construct( | |||
| private JWTTokenManagerInterface $jwtManager, | |||
| private MicroMapperInterface $microMapper, | |||
| private SerializerInterface $serializer, | |||
| private SerializerContextBuilderInterface $serializerContextBuilder | |||
| private JWTTokenManagerInterface $jwtManager | |||
| ) {} | |||
| public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response | |||
| { | |||
| /** @var User $user */ | |||
| $user = $token->getUser(); | |||
| $userApi = $this->microMapper->map($user, UserApi::class); | |||
| $context = [ | |||
| 'groups' => ['Default'], | |||
| 'resource_class' => UserApi::class, | |||
| 'api_normalize' => true, | |||
| 'jsonld_has_context' => true, | |||
| ]; | |||
| $data = $this->serializer->normalize($userApi, 'jsonld', $context); | |||
| $propertyData = [ | |||
| 'dbId' => $userApi->dbId, | |||
| 'email' => $userApi->email, | |||
| 'firstName' => $userApi->firstName, | |||
| 'lastName' => $userApi->lastName, | |||
| 'image' => $userApi->image ? '/api/media_objects/' . $userApi->image->getId() : null, | |||
| 'imageUrl' => $userApi->imageUrl, | |||
| 'fullName' => $userApi->fullName, | |||
| 'roles' => $userApi->roles, | |||
| 'createdAt' => $userApi->createdAt?->format('Y-m-d\TH:i:sP'), | |||
| return new JsonResponse([ | |||
| '@id' => '/api/users/' . $user->getId(), | |||
| 'dbId' => $user->getId(), | |||
| 'token' => $this->jwtManager->create($user) | |||
| ]; | |||
| return new JsonResponse(['user' => $data + $propertyData]); | |||
| ]); | |||
| } | |||
| public function supports(Request $request): ?bool | |||