logout
This commit is contained in:
@@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
|
||||
import { authGuard } from './auth/auth.guard';
|
||||
import { unauthGuard } from './auth/unauth.guard';
|
||||
import { LoginComponent } from './auth/login/login.component';
|
||||
import { LogoutCallbackComponent } from './auth/logout-callback/logout-callback.component';
|
||||
import { SsoCallbackComponent } from './auth/sso-callback/sso-callback.component';
|
||||
import { ListDetailComponent } from './lists/list-detail/list-detail.component';
|
||||
import { ListsComponent } from './lists/lists.component';
|
||||
@@ -12,6 +13,7 @@ export const routes: Routes = [
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'dashboard' },
|
||||
{ path: 'login', component: LoginComponent, canActivate: [unauthGuard] },
|
||||
{ path: 'auth/sso/callback', component: SsoCallbackComponent },
|
||||
{ path: 'auth/sso/logout-callback', component: LogoutCallbackComponent },
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadComponent: () =>
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface AuthTokenResponse {
|
||||
|
||||
export interface AuthLogoutResponse {
|
||||
logoutUrl: string;
|
||||
logoutState: string;
|
||||
}
|
||||
|
||||
export interface RegisterResponse {
|
||||
|
||||
@@ -16,6 +16,7 @@ const ACCESS_TOKEN_KEY = 'listify.accessToken';
|
||||
const REFRESH_TOKEN_KEY = 'listify.refreshToken';
|
||||
const ID_TOKEN_KEY = 'listify.idToken';
|
||||
const USER_KEY = 'listify.user';
|
||||
const LOGOUT_STATE_KEY = 'listify.logoutState';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AuthService {
|
||||
@@ -128,6 +129,7 @@ export class AuthService {
|
||||
|
||||
this.http.post<AuthLogoutResponse>(`${this.apiUrl}/logout`, payload).subscribe({
|
||||
next: (response) => {
|
||||
this.sessionStorage?.setItem(LOGOUT_STATE_KEY, response.logoutState);
|
||||
this.clearSession();
|
||||
window.location.href = response.logoutUrl;
|
||||
},
|
||||
@@ -138,6 +140,15 @@ export class AuthService {
|
||||
});
|
||||
}
|
||||
|
||||
completeProviderLogout(state: string | null): boolean {
|
||||
const expectedState = this.sessionStorage?.getItem(LOGOUT_STATE_KEY) ?? null;
|
||||
|
||||
this.sessionStorage?.removeItem(LOGOUT_STATE_KEY);
|
||||
this.clearSession();
|
||||
|
||||
return Boolean(state && expectedState && state === expectedState);
|
||||
}
|
||||
|
||||
private clearSession(): void {
|
||||
this.storage?.removeItem(ACCESS_TOKEN_KEY);
|
||||
this.storage?.removeItem(REFRESH_TOKEN_KEY);
|
||||
@@ -151,8 +162,6 @@ export class AuthService {
|
||||
this.storage?.setItem(REFRESH_TOKEN_KEY, response.refreshToken);
|
||||
if (response.idToken) {
|
||||
this.storage?.setItem(ID_TOKEN_KEY, response.idToken);
|
||||
} else {
|
||||
this.storage?.removeItem(ID_TOKEN_KEY);
|
||||
}
|
||||
this.storeUser(response.user);
|
||||
}
|
||||
@@ -190,4 +199,8 @@ export class AuthService {
|
||||
private get storage(): Storage | null {
|
||||
return typeof window === 'undefined' ? null : window.localStorage;
|
||||
}
|
||||
|
||||
private get sessionStorage(): Storage | null {
|
||||
return typeof window === 'undefined' ? null : window.sessionStorage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<section class="auth-page">
|
||||
<mat-card class="auth-card verify-card">
|
||||
<div class="auth-logo">
|
||||
<mat-icon>{{ stateIsValid ? 'logout' : 'warning' }}</mat-icon>
|
||||
</div>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Ausgeloggt</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
@if (stateIsValid) {
|
||||
Sie wurden sicher von Listify und Ihrem SSO-Konto abgemeldet.
|
||||
} @else {
|
||||
Die Rückleitung vom SSO-Anbieter konnte nicht bestätigt werden.
|
||||
}
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="verification-state" [class.success]="stateIsValid" [class.error]="!stateIsValid">
|
||||
<mat-icon class="state-icon">{{ stateIsValid ? 'check_circle' : 'error' }}</mat-icon>
|
||||
<p>
|
||||
@if (stateIsValid) {
|
||||
Ihre lokale Sitzung wurde beendet. Sie können dieses Fenster schließen oder sich erneut anmelden.
|
||||
} @else {
|
||||
Ihre lokale Sitzung wurde vorsorglich beendet. Starten Sie eine neue Anmeldung, wenn Sie Listify weiter nutzen möchten.
|
||||
}
|
||||
</p>
|
||||
<a mat-flat-button color="primary" routerLink="/login">
|
||||
<mat-icon aria-hidden="true">login</mat-icon>
|
||||
Erneut anmelden
|
||||
</a>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</section>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-logout-callback',
|
||||
imports: [MatButtonModule, MatCardModule, MatIconModule, RouterLink],
|
||||
templateUrl: './logout-callback.component.html',
|
||||
styleUrl: '../auth-page.scss',
|
||||
})
|
||||
export class LogoutCallbackComponent {
|
||||
private readonly route = inject(ActivatedRoute);
|
||||
private readonly auth = inject(AuthService);
|
||||
|
||||
protected readonly stateIsValid = this.auth.completeProviderLogout(
|
||||
this.route.snapshot.queryParamMap.get('state'),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user