change to firebase auth
This commit is contained in:
parent
b9a9b983e9
commit
a2e6243e93
|
|
@ -58,6 +58,7 @@ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|||
|
||||
pictures
|
||||
pictures_base
|
||||
pictures_
|
||||
|
||||
src/*.js
|
||||
bun.lockb
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch TypeScript file with tsx",
|
||||
"name": "Launch import from exported with tsx",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeArgs": ["tsx", "--inspect"],
|
||||
"args": ["${workspaceFolder}/src/drizzle/import.ts"],
|
||||
"args": ["${workspaceFolder}/src/drizzle/importFromExported.ts"],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js", "!**/node_modules/**"],
|
||||
"sourceMaps": true,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import { APP_INTERCEPTOR } from '@nestjs/core';
|
|||
import { ClsMiddleware, ClsModule } from 'nestjs-cls';
|
||||
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
||||
import { UserInterceptor } from './interceptors/user.interceptor';
|
||||
import { PaymentModule } from './payment/payment.module';
|
||||
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware';
|
||||
import { SelectOptionsModule } from './select-options/select-options.module';
|
||||
import { UserModule } from './user/user.module';
|
||||
|
|
@ -70,7 +69,7 @@ console.log(JSON.stringify(process.env, null, 2));
|
|||
PassportModule,
|
||||
AiModule,
|
||||
LogModule,
|
||||
PaymentModule,
|
||||
// PaymentModule,
|
||||
EventModule,
|
||||
],
|
||||
controllers: [AppController, LogController],
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"@angular/common": "^18.1.3",
|
||||
"@angular/compiler": "^18.1.3",
|
||||
"@angular/core": "^18.1.3",
|
||||
"@angular/fire": "^18.0.1",
|
||||
"@angular/forms": "^18.1.3",
|
||||
"@angular/platform-browser": "^18.1.3",
|
||||
"@angular/platform-browser-dynamic": "^18.1.3",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!-- <div class="container"> -->
|
||||
<div class="flex flex-col" [ngClass]="{ 'bg-slate-100 print:bg-white': actualRoute !== 'home' }">
|
||||
@if (actualRoute !=='home'){
|
||||
@if (actualRoute !=='home' && actualRoute !=='login'){
|
||||
<header></header>
|
||||
}
|
||||
<main class="flex-grow">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { APP_INITIALIZER, ApplicationConfig, ErrorHandler } from '@angular/core'
|
|||
import { provideRouter, withEnabledBlockingInitialNavigation, withInMemoryScrolling } from '@angular/router';
|
||||
|
||||
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
|
||||
import { getAuth, provideAuth } from '@angular/fire/auth';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
import { KeycloakBearerInterceptor, KeycloakService } from 'keycloak-angular';
|
||||
import { GALLERY_CONFIG, GalleryConfig } from 'ng-gallery';
|
||||
|
|
@ -9,7 +11,9 @@ import { provideQuillConfig } from 'ngx-quill';
|
|||
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
|
||||
import { shareIcons } from 'ngx-sharebuttons/icons';
|
||||
import { provideNgxStripe } from 'ngx-stripe';
|
||||
import { environment } from '../environments/environment';
|
||||
import { routes } from './app.routes';
|
||||
import { AuthInterceptor } from './interceptors/auth.interceptor';
|
||||
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
||||
import { TimeoutInterceptor } from './interceptors/timeout.interceptor';
|
||||
import { GlobalErrorHandler } from './services/globalErrorHandler';
|
||||
|
|
@ -52,6 +56,7 @@ export const appConfig: ApplicationConfig = {
|
|||
useClass: TimeoutInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
|
||||
{
|
||||
provide: 'TIMEOUT_DURATION',
|
||||
useValue: 5000, // Standard-Timeout von 5 Sekunden
|
||||
|
|
@ -93,6 +98,9 @@ export const appConfig: ApplicationConfig = {
|
|||
],
|
||||
},
|
||||
}),
|
||||
provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
|
||||
provideAuth(() => getAuth()),
|
||||
// provideFirestore(() => getFirestore()),
|
||||
],
|
||||
};
|
||||
function initServices(selectOptions: SelectOptionsService) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
|
|||
import { LogoutComponent } from './components/logout/logout.component';
|
||||
import { NotFoundComponent } from './components/not-found/not-found.component';
|
||||
|
||||
import { LoginRegisterComponent } from './components/login-register/login-register.component';
|
||||
import { AuthGuard } from './guards/auth.guard';
|
||||
import { ListingCategoryGuard } from './guards/listing-category.guard';
|
||||
import { UserListComponent } from './pages/admin/user-list/user-list.component';
|
||||
|
|
@ -12,7 +13,6 @@ import { HomeComponent } from './pages/home/home.component';
|
|||
import { BrokerListingsComponent } from './pages/listings/broker-listings/broker-listings.component';
|
||||
import { BusinessListingsComponent } from './pages/listings/business-listings/business-listings.component';
|
||||
import { CommercialPropertyListingsComponent } from './pages/listings/commercial-property-listings/commercial-property-listings.component';
|
||||
import { LoginComponent } from './pages/login/login.component';
|
||||
import { PricingComponent } from './pages/pricing/pricing.component';
|
||||
import { AccountComponent } from './pages/subscription/account/account.component';
|
||||
import { EditBusinessListingComponent } from './pages/subscription/edit-business-listing/edit-business-listing.component';
|
||||
|
|
@ -57,9 +57,17 @@ export const routes: Routes = [
|
|||
canActivate: [ListingCategoryGuard],
|
||||
component: NotFoundComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet
|
||||
},
|
||||
// {
|
||||
// path: 'login/:page',
|
||||
// component: LoginComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet
|
||||
// },
|
||||
{
|
||||
path: 'login/:page',
|
||||
component: LoginComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet
|
||||
component: LoginRegisterComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginRegisterComponent, // Dummy-Komponente, wird nie angezeigt, da der Guard weiterleitet
|
||||
},
|
||||
{
|
||||
path: 'notfound',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<div class="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
||||
<div class="bg-white p-8 rounded shadow-md w-full max-w-md text-center">
|
||||
<h2 class="text-2xl font-bold mb-4">Email Verification</h2>
|
||||
<p class="mb-4">A verification email has been sent to your email address. Please check your inbox and click the link to verify your account.</p>
|
||||
<p>Once verified, please return to the application.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-email-verification',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './email-verification.component.html',
|
||||
})
|
||||
export class EmailVerificationComponent {}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<div class="flex flex-col lg:flex-row items-center order-3 lg:order-2">
|
||||
<a class="text-sm text-blue-600 hover:underline hover:cursor-pointer mx-2" data-drawer-target="terms-of-use" data-drawer-show="terms-of-use" aria-controls="terms-of-use">Terms of use</a>
|
||||
<a class="text-sm text-blue-600 hover:underline hover:cursor-pointer mx-2" data-drawer-target="privacy" data-drawer-show="privacy" aria-controls="privacy">Privacy statement</a>
|
||||
<a class="text-sm text-blue-600 hover:underline hover:cursor-pointer mx-2" routerLink="/pricingOverview">Pricing</a>
|
||||
<!-- <a class="text-sm text-blue-600 hover:underline hover:cursor-pointer mx-2" routerLink="/pricingOverview">Pricing</a> -->
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col lg:flex-row items-center order-2 lg:order-3">
|
||||
|
|
|
|||
|
|
@ -135,10 +135,10 @@
|
|||
<div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded-lg shadow dark:bg-gray-700 dark:divide-gray-600" id="user-unknown">
|
||||
<ul class="py-2" aria-labelledby="user-menu-button">
|
||||
<li>
|
||||
<a (click)="login()" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Log In</a>
|
||||
<a routerLink="/login" [queryParams]="{ mode: 'login' }" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Log In</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/pricing" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Register</a>
|
||||
<a routerLink="/login" [queryParams]="{ mode: 'register' }" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Register</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="py-2 md:hidden">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { filter, Observable, Subject, Subscription } from 'rxjs';
|
|||
import { SortByOptions, User } from '../../../../../bizmatch-server/src/models/db.model';
|
||||
import { BusinessListingCriteria, CommercialPropertyListingCriteria, emailToDirName, KeycloakUser, KeyValueAsSortBy, UserListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CriteriaChangeService } from '../../services/criteria-change.service';
|
||||
import { SearchService } from '../../services/search.service';
|
||||
import { SelectOptionsService } from '../../services/select-options.service';
|
||||
|
|
@ -56,6 +57,7 @@ export class HeaderComponent {
|
|||
private searchService: SearchService,
|
||||
private criteriaChangeService: CriteriaChangeService,
|
||||
public selectOptions: SelectOptionsService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
@HostListener('document:click', ['$event'])
|
||||
handleGlobalClick(event: Event) {
|
||||
|
|
@ -65,7 +67,8 @@ export class HeaderComponent {
|
|||
}
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
//const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
if (this.keycloakUser) {
|
||||
this.user = await this.userService.getByMail(this.keycloakUser?.email);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<div class="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
||||
<div class="bg-white p-8 rounded shadow-md w-full max-w-md">
|
||||
<h2 class="text-2xl font-bold mb-6 text-center">
|
||||
{{ isLoginMode ? 'Login' : 'Registrierung' }}
|
||||
</h2>
|
||||
|
||||
<!-- Toggle Switch mit Flowbite -->
|
||||
<div class="flex items-center justify-center mb-6">
|
||||
<span class="mr-3 text-gray-700 font-medium">Login</span>
|
||||
<label for="toggle-switch" class="inline-flex relative items-center cursor-pointer">
|
||||
<input type="checkbox" id="toggle-switch" class="sr-only peer" [checked]="!isLoginMode" (change)="toggleMode()" />
|
||||
<div
|
||||
class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:bg-gray-700 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"
|
||||
></div>
|
||||
</label>
|
||||
<span class="ml-3 text-gray-700 font-medium">Sign Up</span>
|
||||
</div>
|
||||
|
||||
<!-- E-Mail Eingabe -->
|
||||
<div class="mb-4">
|
||||
<label for="email" class="block text-gray-700 mb-2">EMail</label>
|
||||
<input id="email" type="email" [(ngModel)]="email" placeholder="Please enter EMail Address" class="w-full px-3 py-2 border rounded focus:outline-none focus:border-blue-500" />
|
||||
</div>
|
||||
|
||||
<!-- Passwort Eingabe -->
|
||||
<div class="mb-4">
|
||||
<label for="password" class="block text-gray-700 mb-2">Password</label>
|
||||
<input id="password" type="password" [(ngModel)]="password" placeholder="Please enter Passwort" class="w-full px-3 py-2 border rounded focus:outline-none focus:border-blue-500" />
|
||||
</div>
|
||||
|
||||
<!-- Passwort-Bestätigung nur im Registrierungsmodus -->
|
||||
<div *ngIf="!isLoginMode" class="mb-6">
|
||||
<label for="confirmPassword" class="block text-gray-700 mb-2">Confirm Password</label>
|
||||
<input id="confirmPassword" type="password" [(ngModel)]="confirmPassword" placeholder="Repeat Password" class="w-full px-3 py-2 border rounded focus:outline-none focus:border-blue-500" />
|
||||
</div>
|
||||
<div *ngIf="errorMessage" class="text-red-500 text-center mb-4">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<button (click)="onSubmit()" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 rounded-lg mb-4">
|
||||
{{ isLoginMode ? 'Sign in with Email' : 'Register' }}
|
||||
</button>
|
||||
|
||||
<div class="flex items-center justify-center my-4">
|
||||
<span class="border-b w-1/5 md:w-1/4"></span>
|
||||
<span class="text-xs text-center text-gray-500 uppercase mx-2">or</span>
|
||||
<span class="border-b w-1/5 md:w-1/4"></span>
|
||||
</div>
|
||||
|
||||
<button (click)="loginWithGoogle()" class="w-full bg-red-500 hover:bg-red-600 text-white py-2 rounded-lg">Continue with Google</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login-register',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './login-register.component.html',
|
||||
})
|
||||
export class LoginRegisterComponent {
|
||||
email: string = '';
|
||||
password: string = '';
|
||||
confirmPassword: string = '';
|
||||
isLoginMode: boolean = true; // true: Login, false: Registration
|
||||
errorMessage: string = '';
|
||||
|
||||
constructor(private authService: AuthService, private route: ActivatedRoute, private router: Router) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Set mode based on query parameter "mode"
|
||||
this.route.queryParamMap.subscribe(params => {
|
||||
const mode = params.get('mode');
|
||||
this.isLoginMode = mode !== 'register';
|
||||
});
|
||||
}
|
||||
|
||||
toggleMode(): void {
|
||||
this.isLoginMode = !this.isLoginMode;
|
||||
this.errorMessage = '';
|
||||
}
|
||||
|
||||
// Login with Email
|
||||
onSubmit(): void {
|
||||
this.errorMessage = '';
|
||||
if (this.isLoginMode) {
|
||||
this.authService
|
||||
.loginWithEmail(this.email, this.password)
|
||||
.then(userCredential => {
|
||||
console.log('Successfully logged in:', userCredential);
|
||||
this.router.navigate([`home`]);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during email login:', error);
|
||||
this.errorMessage = error.message;
|
||||
});
|
||||
} else {
|
||||
// Registration mode: also check if passwords match
|
||||
if (this.password !== this.confirmPassword) {
|
||||
console.error('Passwords do not match');
|
||||
this.errorMessage = 'Passwords do not match.';
|
||||
return;
|
||||
}
|
||||
this.authService
|
||||
.registerWithEmail(this.email, this.password)
|
||||
.then(userCredential => {
|
||||
console.log('Successfully registered:', userCredential);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during registration:', error);
|
||||
if (error.code === 'auth/email-already-in-use') {
|
||||
this.errorMessage = 'This email address is already in use. Please try logging in.';
|
||||
} else {
|
||||
this.errorMessage = error.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Login with Google
|
||||
loginWithGoogle(): void {
|
||||
this.errorMessage = '';
|
||||
this.authService
|
||||
.loginWithGoogle()
|
||||
.then(userCredential => {
|
||||
console.log('Successfully logged in with Google:', userCredential);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during Google login:', error);
|
||||
this.errorMessage = error.message;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { Router, RouterModule } from '@angular/router';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'logout',
|
||||
|
|
@ -10,8 +11,10 @@ import { KeycloakService } from 'keycloak-angular';
|
|||
template: ``,
|
||||
})
|
||||
export class LogoutComponent {
|
||||
constructor(public keycloakService: KeycloakService) {
|
||||
sessionStorage.removeItem('USERID');
|
||||
keycloakService.logout(window.location.origin + '/home');
|
||||
constructor(public keycloakService: KeycloakService, private authService: AuthService, private router: Router) {
|
||||
//sessionStorage.removeItem('USERID');
|
||||
//keycloakService.logout(window.location.origin + '/home');
|
||||
this.authService.logout();
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,54 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
|
||||
import { KeycloakInitializerService } from '../services/keycloak-initializer.service';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { createLogger } from '../utils/utils';
|
||||
const logger = createLogger('AuthGuard');
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthGuard extends KeycloakAuthGuard {
|
||||
constructor(protected override readonly router: Router, protected readonly keycloak: KeycloakService, private keycloakInitializer: KeycloakInitializerService) {
|
||||
super(router, keycloak);
|
||||
}
|
||||
// export class AuthGuard extends KeycloakAuthGuard {
|
||||
// constructor(protected override readonly router: Router, protected readonly keycloak: KeycloakService, private keycloakInitializer: KeycloakInitializerService) {
|
||||
// super(router, keycloak);
|
||||
// }
|
||||
|
||||
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean | UrlTree> {
|
||||
logger.info(`--->AuthGuard`);
|
||||
while (!this.keycloakInitializer.initialized) {
|
||||
logger.info(`Waiting 100 msec`);
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
// Force the user to log in if currently unauthenticated.
|
||||
const authenticated = this.keycloak.isLoggedIn();
|
||||
//this.keycloak.isTokenExpired()
|
||||
if (!this.authenticated && !authenticated) {
|
||||
await this.keycloak.login({
|
||||
redirectUri: window.location.origin + state.url,
|
||||
});
|
||||
// return false;
|
||||
}
|
||||
// async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean | UrlTree> {
|
||||
// logger.info(`--->AuthGuard`);
|
||||
// while (!this.keycloakInitializer.initialized) {
|
||||
// logger.info(`Waiting 100 msec`);
|
||||
// await new Promise(resolve => setTimeout(resolve, 100));
|
||||
// }
|
||||
// // Force the user to log in if currently unauthenticated.
|
||||
// const authenticated = this.keycloak.isLoggedIn();
|
||||
// //this.keycloak.isTokenExpired()
|
||||
// if (!this.authenticated && !authenticated) {
|
||||
// await this.keycloak.login({
|
||||
// redirectUri: window.location.origin + state.url,
|
||||
// });
|
||||
// // return false;
|
||||
// }
|
||||
|
||||
// Get the roles required from the route.
|
||||
const requiredRoles = route.data['roles'];
|
||||
// // Get the roles required from the route.
|
||||
// const requiredRoles = route.data['roles'];
|
||||
|
||||
// Allow the user to proceed if no additional roles are required to access the route.
|
||||
if (!Array.isArray(requiredRoles) || requiredRoles.length === 0) {
|
||||
// // Allow the user to proceed if no additional roles are required to access the route.
|
||||
// if (!Array.isArray(requiredRoles) || requiredRoles.length === 0) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// // Allow the user to proceed if all the required roles are present.
|
||||
// return requiredRoles.every(role => this.roles.includes(role));
|
||||
// }
|
||||
// }
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
async canActivate(): Promise<boolean> {
|
||||
const token = await this.authService.getToken();
|
||||
if (token) {
|
||||
return true;
|
||||
} else {
|
||||
this.router.navigate(['/login-register']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow the user to proceed if all the required roles are present.
|
||||
return requiredRoles.every(role => this.roles.includes(role));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// auth.interceptor.ts
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthInterceptor implements HttpInterceptor {
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return from(this.authService.getToken()).pipe(
|
||||
switchMap(token => {
|
||||
if (token) {
|
||||
const clonedReq = req.clone({
|
||||
setHeaders: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
return next.handle(clonedReq);
|
||||
}
|
||||
return next.handle(req);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import { SharedModule } from '../../../shared/shared/shared.module';
|
|||
import { createMailInfo, map2User } from '../../../utils/utils';
|
||||
// Import für Leaflet
|
||||
// Benannte Importe für Leaflet
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { BaseDetailsComponent } from '../base-details.component';
|
||||
@Component({
|
||||
selector: 'app-details-business-listing',
|
||||
|
|
@ -80,6 +81,7 @@ export class DetailsBusinessListingComponent extends BaseDetailsComponent {
|
|||
private auditService: AuditService,
|
||||
public emailService: EMailService,
|
||||
private geoService: GeoService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
super();
|
||||
this.router.events.subscribe(event => {
|
||||
|
|
@ -92,7 +94,8 @@ export class DetailsBusinessListingComponent extends BaseDetailsComponent {
|
|||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
if (this.keycloakUser) {
|
||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { ValidatedNgSelectComponent } from '../../../components/validated-ng-sel
|
|||
import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||
import { AuditService } from '../../../services/audit.service';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { HistoryService } from '../../../services/history.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
|
|
@ -84,13 +85,15 @@ export class DetailsCommercialPropertyListingComponent extends BaseDetailsCompon
|
|||
private messageService: MessageService,
|
||||
private auditService: AuditService,
|
||||
private emailService: EMailService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
super();
|
||||
this.mailinfo = { sender: {}, email: '', url: environment.mailinfoUrl };
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
if (this.keycloakUser) {
|
||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Observable } from 'rxjs';
|
|||
import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { KeycloakUser, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { HistoryService } from '../../../services/history.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
|
|
@ -46,6 +47,7 @@ export class DetailsUserComponent {
|
|||
private imageService: ImageService,
|
||||
public historyService: HistoryService,
|
||||
public keycloakService: KeycloakService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
|
|
@ -55,7 +57,8 @@ export class DetailsUserComponent {
|
|||
this.businessListings = results[0];
|
||||
this.commercialPropListings = results[1] as CommercialPropertyListing[];
|
||||
//this.user$ = this.userService.getUserObservable();
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
this.companyOverview = this.sanitizer.bypassSecurityTrustHtml(this.user.companyOverview ? this.user.companyOverview : '');
|
||||
this.offeredServices = this.sanitizer.bypassSecurityTrustHtml(this.user.offeredServices ? this.user.offeredServices : '');
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
<a routerLink="/account" class="text-blue-600 border border-blue-600 px-3 py-2 rounded">Account</a>
|
||||
} @else {
|
||||
<!-- <a routerLink="/pricing" class="text-gray-800">Pricing</a> -->
|
||||
<a (click)="login()" class="text-blue-600 border border-blue-600 px-3 py-2 rounded">Log In</a>
|
||||
<a routerLink="/pricing" class="text-white bg-blue-600 px-4 py-2 rounded">Register</a>
|
||||
<a routerLink="/login" [queryParams]="{ mode: 'login' }" class="text-blue-600 border border-blue-600 px-3 py-2 rounded">Log In</a>
|
||||
<a routerLink="/login" [queryParams]="{ mode: 'register' }" class="text-white bg-blue-600 px-4 py-2 rounded">Register</a>
|
||||
<!-- <a routerLink="/login" class="text-blue-500 hover:underline">Login/Register</a> -->
|
||||
}
|
||||
</div>
|
||||
<button (click)="toggleMenu()" class="md:hidden text-gray-600">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { BusinessListingCriteria, CityAndStateResult, CommercialPropertyListingC
|
|||
import { ModalService } from '../../components/search-modal/modal.service';
|
||||
import { TooltipComponent } from '../../components/tooltip/tooltip.component';
|
||||
import { AiService } from '../../services/ai.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CriteriaChangeService } from '../../services/criteria-change.service';
|
||||
import { GeoService } from '../../services/geo.service';
|
||||
import { ListingsService } from '../../services/listings.service';
|
||||
|
|
@ -78,12 +79,14 @@ export class HomeComponent {
|
|||
private listingService: ListingsService,
|
||||
private userService: UserService,
|
||||
private aiService: AiService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
setTimeout(() => {
|
||||
initFlowbite();
|
||||
}, 0);
|
||||
const token = await this.keycloakService.getToken();
|
||||
//const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
sessionStorage.removeItem('businessListings');
|
||||
sessionStorage.removeItem('commercialPropertyListings');
|
||||
sessionStorage.removeItem('brokerListings');
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Component } from '@angular/core';
|
|||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { SubscriptionsService } from '../../services/subscriptions.service';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { map2User } from '../../utils/utils';
|
||||
|
|
@ -15,9 +16,17 @@ import { map2User } from '../../utils/utils';
|
|||
})
|
||||
export class LoginComponent {
|
||||
page: string | undefined = this.activatedRoute.snapshot.params['page'] as string | undefined;
|
||||
constructor(public userService: UserService, private activatedRoute: ActivatedRoute, private keycloakService: KeycloakService, private router: Router, private subscriptionService: SubscriptionsService) {}
|
||||
constructor(
|
||||
public userService: UserService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private keycloakService: KeycloakService,
|
||||
private router: Router,
|
||||
private subscriptionService: SubscriptionsService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
const user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { User } from '../../../../../bizmatch-server/src/models/db.model';
|
|||
import { Checkout, KeycloakUser } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { AuditService } from '../../services/audit.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { SharedModule } from '../../shared/shared/shared.module';
|
||||
import { map2User } from '../../utils/utils';
|
||||
|
|
@ -33,10 +34,12 @@ export class PricingComponent {
|
|||
private userService: UserService,
|
||||
private router: Router,
|
||||
private auditService: AuditService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
if (this.keycloakUser) {
|
||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { ValidatedLocationComponent } from '../../../components/validated-locati
|
|||
import { ValidatedQuillComponent } from '../../../components/validated-quill/validated-quill.component';
|
||||
import { ValidatedSelectComponent } from '../../../components/validated-select/validated-select.component';
|
||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
|
|
@ -97,6 +98,7 @@ export class AccountComponent {
|
|||
private subscriptionService: SubscriptionsService,
|
||||
private datePipe: DatePipe,
|
||||
private router: Router,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
setTimeout(() => {
|
||||
|
|
@ -105,7 +107,8 @@ export class AccountComponent {
|
|||
if (this.id) {
|
||||
this.user = await this.userService.getById(this.id);
|
||||
} else {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
this.user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { ValidatedQuillComponent } from '../../../components/validated-quill/val
|
|||
import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
|
|
@ -87,6 +88,7 @@ export class EditBusinessListingComponent {
|
|||
private route: ActivatedRoute,
|
||||
private keycloakService: KeycloakService,
|
||||
private validationMessagesService: ValidationMessagesService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
|
|
@ -103,7 +105,8 @@ export class EditBusinessListingComponent {
|
|||
});
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
this.listingUser = await this.userService.getByMail(keycloakUser.email);
|
||||
if (this.mode === 'edit') {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { ValidatedPriceComponent } from '../../../components/validated-price/val
|
|||
import { ValidatedQuillComponent } from '../../../components/validated-quill/validated-quill.component';
|
||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
|
|
@ -128,6 +129,7 @@ export class EditCommercialPropertyListingComponent {
|
|||
private messageService: MessageService,
|
||||
private viewportRuler: ViewportRuler,
|
||||
private validationMessagesService: ValidationMessagesService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
// Abonniere Router-Events, um den aktiven Link zu ermitteln
|
||||
this.router.events.subscribe(event => {
|
||||
|
|
@ -145,7 +147,8 @@ export class EditCommercialPropertyListingComponent {
|
|||
});
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
this.user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { ValidatedNgSelectComponent } from '../../../components/validated-ng-sel
|
|||
import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||
import { AuditService } from '../../../services/audit.service';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { MailService } from '../../../services/mail.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
|
|
@ -35,11 +36,13 @@ export class EmailUsComponent {
|
|||
private messageService: MessageService,
|
||||
public selectOptions: SelectOptionsService,
|
||||
private auditService: AuditService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
this.mailinfo = createMailInfo();
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
if (this.keycloakUser) {
|
||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { BusinessListing, CommercialPropertyListing } from '../../../../../../bi
|
|||
import { KeycloakUser } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { ConfirmationComponent } from '../../../components/confirmation/confirmation.component';
|
||||
import { ConfirmationService } from '../../../components/confirmation/confirmation.service';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
|
|
@ -20,9 +21,16 @@ export class FavoritesComponent {
|
|||
user: KeycloakUser;
|
||||
// listings: Array<ListingType> = []; //= dataListings as unknown as Array<BusinessListing>;
|
||||
favorites: Array<BusinessListing | CommercialPropertyListing>;
|
||||
constructor(public keycloakService: KeycloakService, private listingsService: ListingsService, public selectOptions: SelectOptionsService, private confirmationService: ConfirmationService) {}
|
||||
constructor(
|
||||
public keycloakService: KeycloakService,
|
||||
private listingsService: ListingsService,
|
||||
public selectOptions: SelectOptionsService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
this.user = map2User(token);
|
||||
const result = await Promise.all([await this.listingsService.getFavoriteListings('business'), await this.listingsService.getFavoriteListings('commercialProperty')]);
|
||||
this.favorites = [...result[0], ...result[1]];
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { ConfirmationComponent } from '../../../components/confirmation/confirma
|
|||
import { ConfirmationService } from '../../../components/confirmation/confirmation.service';
|
||||
import { MessageComponent } from '../../../components/message/message.component';
|
||||
import { MessageService } from '../../../components/message/message.service';
|
||||
import { AuthService } from '../../../services/auth.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
|
|
@ -32,10 +33,12 @@ export class MyListingComponent {
|
|||
public selectOptions: SelectOptionsService,
|
||||
private messageService: MessageService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
// const keycloakUser = this.userService.getKeycloakUser();
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
this.user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Router, RouterModule } from '@angular/router';
|
|||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { User } from '../../../../../bizmatch-server/src/models/db.model';
|
||||
import { AuditService } from '../../services/audit.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { map2User } from '../../utils/utils';
|
||||
|
||||
|
|
@ -18,12 +19,13 @@ export class SuccessComponent {
|
|||
user: User;
|
||||
maxAttemptsReached: boolean = false; // Neue Variable hinzufügen
|
||||
|
||||
constructor(private keycloakService: KeycloakService, private userService: UserService, private auditService: AuditService, private router: Router) {}
|
||||
constructor(private keycloakService: KeycloakService, private userService: UserService, private auditService: AuditService, private router: Router, private authService: AuthService) {}
|
||||
|
||||
async ngOnInit() {
|
||||
let email = null;
|
||||
try {
|
||||
const token = await this.keycloakService.getToken();
|
||||
// const token = await this.keycloakService.getToken();
|
||||
const token = await this.authService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
email = keycloakUser.email;
|
||||
this.user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
// auth.service.ts
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { FirebaseApp } from '@angular/fire/app';
|
||||
import { GoogleAuthProvider, UserCredential, createUserWithEmailAndPassword, getAuth, sendEmailVerification, signInWithEmailAndPassword, signInWithPopup } from 'firebase/auth';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthService {
|
||||
private app = inject(FirebaseApp);
|
||||
private auth = getAuth(this.app);
|
||||
private http = inject(HttpClient);
|
||||
|
||||
// Registrierung mit Email und Passwort
|
||||
async registerWithEmail(email: string, password: string): Promise<UserCredential> {
|
||||
const userCredential = await createUserWithEmailAndPassword(this.auth, email, password);
|
||||
|
||||
// E-Mail-Verifizierung senden
|
||||
if (userCredential.user) {
|
||||
await sendEmailVerification(userCredential.user);
|
||||
}
|
||||
|
||||
// Token, RefreshToken und ggf. photoURL speichern
|
||||
const token = await userCredential.user.getIdToken();
|
||||
localStorage.setItem('authToken', token);
|
||||
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
|
||||
if (userCredential.user.photoURL) {
|
||||
localStorage.setItem('photoURL', userCredential.user.photoURL);
|
||||
}
|
||||
|
||||
return userCredential;
|
||||
}
|
||||
|
||||
// Login mit Email und Passwort
|
||||
loginWithEmail(email: string, password: string): Promise<UserCredential> {
|
||||
return signInWithEmailAndPassword(this.auth, email, password).then(async userCredential => {
|
||||
if (userCredential.user) {
|
||||
const token = await userCredential.user.getIdToken();
|
||||
localStorage.setItem('authToken', token);
|
||||
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
|
||||
if (userCredential.user.photoURL) {
|
||||
localStorage.setItem('photoURL', userCredential.user.photoURL);
|
||||
}
|
||||
}
|
||||
return userCredential;
|
||||
});
|
||||
}
|
||||
|
||||
// Login mit Google
|
||||
loginWithGoogle(): Promise<UserCredential> {
|
||||
const provider = new GoogleAuthProvider();
|
||||
return signInWithPopup(this.auth, provider).then(async userCredential => {
|
||||
if (userCredential.user) {
|
||||
const token = await userCredential.user.getIdToken();
|
||||
localStorage.setItem('authToken', token);
|
||||
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
|
||||
if (userCredential.user.photoURL) {
|
||||
localStorage.setItem('photoURL', userCredential.user.photoURL);
|
||||
}
|
||||
}
|
||||
return userCredential;
|
||||
});
|
||||
}
|
||||
|
||||
// Logout: Token, RefreshToken und photoURL entfernen
|
||||
logout(): Promise<void> {
|
||||
localStorage.removeItem('authToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
localStorage.removeItem('photoURL');
|
||||
return this.auth.signOut();
|
||||
}
|
||||
|
||||
// Prüft, ob ein Token noch gültig ist (über die "exp"-Eigenschaft)
|
||||
private isTokenValid(token: string): boolean {
|
||||
try {
|
||||
const payloadBase64 = token.split('.')[1];
|
||||
const payloadJson = atob(payloadBase64.replace(/-/g, '+').replace(/_/g, '/'));
|
||||
const payload = JSON.parse(payloadJson);
|
||||
const exp = payload.exp;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return exp > now;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Versucht, mit dem RefreshToken einen neuen Access Token zu erhalten
|
||||
async refreshToken(): Promise<string | null> {
|
||||
const storedRefreshToken = localStorage.getItem('refreshToken');
|
||||
if (!storedRefreshToken) {
|
||||
return null;
|
||||
}
|
||||
const apiKey = environment.firebaseConfig.apiKey; // Stelle sicher, dass dieser Wert in Deiner environment.ts gesetzt ist
|
||||
const url = `https://securetoken.googleapis.com/v1/token?key=${apiKey}`;
|
||||
|
||||
const body = new HttpParams().set('grant_type', 'refresh_token').set('refresh_token', storedRefreshToken);
|
||||
|
||||
const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
|
||||
|
||||
try {
|
||||
const response: any = await firstValueFrom(this.http.post(url, body.toString(), { headers }));
|
||||
// response enthält z. B. id_token, refresh_token, expires_in etc.
|
||||
const newToken = response.id_token;
|
||||
const newRefreshToken = response.refresh_token;
|
||||
localStorage.setItem('authToken', newToken);
|
||||
localStorage.setItem('refreshToken', newRefreshToken);
|
||||
return newToken;
|
||||
} catch (error) {
|
||||
console.error('Error refreshing token:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen gültigen Token zurück.
|
||||
* Falls der gespeicherte Token noch gültig ist, wird er zurückgegeben.
|
||||
* Ansonsten wird versucht, einen neuen Token mit dem RefreshToken zu holen.
|
||||
* Ist auch das nicht möglich, wird null zurückgegeben.
|
||||
*/
|
||||
async getToken(): Promise<string | null> {
|
||||
const token = localStorage.getItem('authToken');
|
||||
if (token && this.isTokenValid(token)) {
|
||||
return token;
|
||||
} else {
|
||||
return await this.refreshToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ export function routeListingWithState(router: Router, value: string, data: any)
|
|||
}
|
||||
}
|
||||
|
||||
export function map2User(jwt: string): KeycloakUser {
|
||||
export function map2User(jwt: string | null): KeycloakUser {
|
||||
if (jwt) {
|
||||
const token = jwtDecode<JwtToken>(jwt);
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -12,4 +12,13 @@ export const environment_base = {
|
|||
redirectUri: 'https://dev.bizmatch.net',
|
||||
},
|
||||
ipinfo_token: '7029590fb91214',
|
||||
firebaseConfig: {
|
||||
apiKey: 'AIzaSyBqVutQqdgUzwD9tKiKJrJq2Q6rD1hNdzw',
|
||||
authDomain: 'bizmatch-net.firebaseapp.com',
|
||||
projectId: 'bizmatch-net',
|
||||
storageBucket: 'bizmatch-net.firebasestorage.app',
|
||||
messagingSenderId: '1065122571067',
|
||||
appId: '1:1065122571067:web:1124571ab67bc0f5240d1e',
|
||||
measurementId: 'G-MHVDK1KSWV',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue