| @@ -2925,9 +2925,15 @@ components: | |||||
| AuthResponse: | AuthResponse: | ||||
| type: object | type: object | ||||
| properties: | 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: { } | responses: { } | ||||
| parameters: { } | parameters: { } | ||||
| examples: { } | examples: { } | ||||
| @@ -197,5 +197,6 @@ export const credentialsForm = new FormGroup({ | |||||
| }); | }); | ||||
| export const authResponseForm = 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 { Injectable } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | import { Router } from '@angular/router'; | ||||
| import { HttpClient } from '@angular/common/http'; | import { HttpClient } from '@angular/common/http'; | ||||
| import { BehaviorSubject, Observable } from 'rxjs'; | |||||
| import { BehaviorSubject, Observable, switchMap } from 'rxjs'; | |||||
| import { map } from 'rxjs/operators'; | 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' }) | @Injectable({ providedIn: 'root' }) | ||||
| export class AccountService { | export class AccountService { | ||||
| private userSubject: BehaviorSubject<UserJsonld | null>; | private userSubject: BehaviorSubject<UserJsonld | null>; | ||||
| public user: Observable<UserJsonld | null>; | public user: Observable<UserJsonld | null>; | ||||
| constructor( | constructor( | ||||
| private router: Router, | private router: Router, | ||||
| private http: HttpClient, | 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(); | this.user = this.userSubject.asObservable(); | ||||
| } | } | ||||
| @@ -28,16 +36,25 @@ export class AccountService { | |||||
| login(email: string, password: string) { | login(email: string, password: string) { | ||||
| return this.authService.postCredentialsItem({ email, password }) | 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() { | logout() { | ||||
| // remove user from local storage and set current user to null | |||||
| localStorage.removeItem('user'); | localStorage.removeItem('user'); | ||||
| localStorage.removeItem('token'); | |||||
| this.userSubject.next(null); | this.userSubject.next(null); | ||||
| this.router.navigate(['/account/login']); | this.router.navigate(['/account/login']); | ||||
| } | } | ||||
| @@ -46,17 +63,11 @@ export class AccountService { | |||||
| return this.userValue !== null; | 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 { | 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 { | export function apiConfigFactory(): Configuration { | ||||
| const params: ConfigurationParameters = { | const params: ConfigurationParameters = { | ||||
| basePath: environment.basePath, | basePath: environment.basePath, | ||||
| withCredentials: false | |||||
| withCredentials: false, | |||||
| credentials: { | |||||
| 'JWT': () => localStorage.getItem('token') || undefined | |||||
| } | |||||
| }; | }; | ||||
| return new Configuration(params); | return new Configuration(params); | ||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| .gitignore | .gitignore | ||||
| .openapi-generator-ignore | |||||
| README.md | README.md | ||||
| api.module.ts | api.module.ts | ||||
| api/api.ts | api/api.ts | ||||
| @@ -9,10 +9,11 @@ | |||||
| * https://openapi-generator.tech | * https://openapi-generator.tech | ||||
| * Do not edit the class manually. | * Do not edit the class manually. | ||||
| */ | */ | ||||
| import { UserJsonld } from './userJsonld'; | |||||
| export interface AuthResponse { | 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)] | #[ApiProperty(writable: false)] | ||||
| public array $roles = []; | public array $roles = []; | ||||
| #[ApiProperty(writable: false)] | |||||
| public ?string $token = null; | |||||
| #[ApiProperty(writable: false)] | #[ApiProperty(writable: false)] | ||||
| public ?\DateTimeImmutable $createdAt = null; | public ?\DateTimeImmutable $createdAt = null; | ||||
| @@ -38,10 +38,18 @@ final class AuthDecorator implements OpenApiFactoryInterface | |||||
| $schemas['AuthResponse'] = new \ArrayObject([ | $schemas['AuthResponse'] = new \ArrayObject([ | ||||
| 'type' => 'object', | 'type' => 'object', | ||||
| 'properties' => [ | '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 | class JwtAuthenticator extends AbstractAuthenticator | ||||
| { | { | ||||
| public function __construct( | 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 | public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response | ||||
| { | { | ||||
| /** @var User $user */ | /** @var User $user */ | ||||
| $user = $token->getUser(); | $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) | 'token' => $this->jwtManager->create($user) | ||||
| ]; | |||||
| return new JsonResponse(['user' => $data + $propertyData]); | |||||
| ]); | |||||
| } | } | ||||
| public function supports(Request $request): ?bool | public function supports(Request $request): ?bool | ||||