Reviewed-on: #108
This commit is contained in:
commit
cd75967b4f
6 changed files with 87 additions and 65 deletions
|
@ -8,7 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="centerNav"></div>
|
<div class="centerNav"></div>
|
||||||
<div class="rightNav">
|
<div class="rightNav">
|
||||||
@if (auth.loggedIn) {
|
@if (auth.isAuth()) {
|
||||||
<button class="ybtn sbButton">
|
<button class="ybtn sbButton">
|
||||||
<a (click)="logout()" class="logout">Logout</a>
|
<a (click)="logout()" class="logout">Logout</a>
|
||||||
</button>
|
</button>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@if (auth.loggedIn) {
|
@if (auth.isAuth()) {
|
||||||
<app-navigation [events]="toggleNavSubject.asObservable()"></app-navigation>
|
<app-navigation [events]="toggleNavSubject.asObservable()"></app-navigation>
|
||||||
} @else {
|
} @else {
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function authIntercept(
|
||||||
next: HttpHandlerFn,
|
next: HttpHandlerFn,
|
||||||
): Observable<HttpEvent<unknown>> {
|
): Observable<HttpEvent<unknown>> {
|
||||||
let authSvc: AuthService = inject(AuthService);
|
let authSvc: AuthService = inject(AuthService);
|
||||||
if (authSvc.loggedIn) {
|
if (authSvc.isAuth()) {
|
||||||
req = req.clone({
|
req = req.clone({
|
||||||
setHeaders: {
|
setHeaders: {
|
||||||
Authorization: `Bearer ${authSvc.getToken()}`,
|
Authorization: `Bearer ${authSvc.getToken()}`,
|
||||||
|
|
|
@ -1,56 +1,92 @@
|
||||||
import { Injectable } from '@angular/core';
|
import {
|
||||||
|
Injectable,
|
||||||
|
signal,
|
||||||
|
computed,
|
||||||
|
effect,
|
||||||
|
inject,
|
||||||
|
DestroyRef,
|
||||||
|
} from '@angular/core';
|
||||||
import { HttpClient, HttpResponse } from '@angular/common/http';
|
import { HttpClient, HttpResponse } from '@angular/common/http';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
export class Jwt {
|
export class Jwt {
|
||||||
constructor(public jwt: string) {}
|
constructor(public jwt: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthState = {
|
||||||
|
user: string | null;
|
||||||
|
token: string | null;
|
||||||
|
is_auth: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
loggedIn: boolean = false;
|
private _accessTokenKey = 'jwt';
|
||||||
|
private _storedToken = localStorage.getItem(this._accessTokenKey);
|
||||||
|
destroyed = inject(DestroyRef);
|
||||||
|
|
||||||
|
private _state = signal<AuthState>({
|
||||||
|
user: null,
|
||||||
|
token: this._storedToken,
|
||||||
|
is_auth: this._storedToken !== null,
|
||||||
|
});
|
||||||
|
loginFailed = signal<boolean>(false);
|
||||||
|
token = computed(() => this._state().token);
|
||||||
|
isAuth = computed(() => this._state().is_auth);
|
||||||
|
user = computed(() => this._state().user);
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private _router: Router,
|
private _router: Router,
|
||||||
) {
|
) {
|
||||||
let ssJWT = localStorage.getItem('jwt');
|
effect(() => {
|
||||||
if (ssJWT) {
|
const token = this.token();
|
||||||
this.loggedIn = true;
|
if (token !== null) {
|
||||||
}
|
localStorage.setItem(this._accessTokenKey, token);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(this._accessTokenKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
login(username: string, password: string): Observable<HttpResponse<Jwt>> {
|
login(username: string, password: string) {
|
||||||
return this.http
|
return this.http
|
||||||
.post<Jwt>(
|
.post<Jwt>('/api/login', { username: username, password: password })
|
||||||
'/api/login',
|
.pipe(takeUntilDestroyed(this.destroyed))
|
||||||
{ username: username, password: password },
|
.subscribe({
|
||||||
{ observe: 'response' },
|
next: (res) => {
|
||||||
)
|
let state = <AuthState>{
|
||||||
.pipe(
|
user: username,
|
||||||
tap((event) => {
|
token: res.jwt,
|
||||||
if (event.status == 200) {
|
is_auth: true,
|
||||||
localStorage.setItem('jwt', event.body?.jwt.toString() ?? '');
|
};
|
||||||
this.loggedIn = true;
|
this._state.set(state);
|
||||||
this._router.navigateByUrl('/home');
|
this.loginFailed.update(() => false);
|
||||||
}
|
this._router.navigateByUrl('/');
|
||||||
}),
|
},
|
||||||
);
|
error: (err) => {
|
||||||
|
this.loginFailed.update(() => true);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearState() {
|
||||||
|
this._state.set(<AuthState>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
this.http
|
this.http.get('/api/logout', { withCredentials: true }).subscribe({
|
||||||
.get('/api/logout', { withCredentials: true, observe: 'response' })
|
next: (event) => {
|
||||||
.subscribe((event) => {
|
this._clearState();
|
||||||
if (event.status == 200) {
|
},
|
||||||
this.loggedIn = false;
|
error: (err) => {
|
||||||
}
|
this._clearState();
|
||||||
});
|
},
|
||||||
localStorage.removeItem('jwt');
|
});
|
||||||
this.loggedIn = false;
|
|
||||||
this._router.navigateByUrl('/login');
|
this._router.navigateByUrl('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,14 +96,20 @@ export class AuthService {
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((event) => {
|
tap((event) => {
|
||||||
if (event.status == 200) {
|
if (event.status == 200) {
|
||||||
localStorage.setItem('jwt', event.body?.jwt.toString() ?? '');
|
let ost = this._state();
|
||||||
this.loggedIn = true;
|
let tok = event.body?.jwt.toString();
|
||||||
|
let state = <AuthState>{
|
||||||
|
user: ost.user,
|
||||||
|
token: tok ? tok : null,
|
||||||
|
is_auth: true,
|
||||||
|
};
|
||||||
|
this._state.set(state);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getToken(): string | null {
|
getToken(): string | null {
|
||||||
return localStorage.getItem('jwt');
|
return localStorage.getItem(this._accessTokenKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<button class="login sbButton" (click)="onSubmit()">Login</button>
|
<button class="login sbButton" (click)="onSubmit()">Login</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@if (failed) {
|
@if (failed()) {
|
||||||
<div role="alert">
|
<div role="alert">
|
||||||
<span>Login Failed!</span>
|
<span>Login Failed!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { AuthService } from '../login/auth.service';
|
import { AuthService } from '../login/auth.service';
|
||||||
import { catchError, of, Subscription } from 'rxjs';
|
import { catchError, of, Subscription } from 'rxjs';
|
||||||
|
@ -17,31 +17,9 @@ export class LoginComponent {
|
||||||
router: Router = inject(Router);
|
router: Router = inject(Router);
|
||||||
username: string = '';
|
username: string = '';
|
||||||
password: string = '';
|
password: string = '';
|
||||||
failed: boolean = false;
|
failed = this.apiService.loginFailed;
|
||||||
private subscriptions = new Subscription();
|
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.failed = false;
|
this.apiService.login(this.username, this.password);
|
||||||
this.subscriptions.add(
|
|
||||||
this.apiService
|
|
||||||
.login(this.username, this.password)
|
|
||||||
.pipe(
|
|
||||||
catchError(() => {
|
|
||||||
this.failed = true;
|
|
||||||
return of(null);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.subscribe((event) => {
|
|
||||||
if (event?.status == 200) {
|
|
||||||
this.router.navigateByUrl('/');
|
|
||||||
} else {
|
|
||||||
this.failed = true;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.subscriptions.unsubscribe();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export class TalkgroupService {
|
||||||
if (sh) {
|
if (sh) {
|
||||||
this.shareSvc.getShare(sh).subscribe(this.fetchAll);
|
this.shareSvc.getShare(sh).subscribe(this.fetchAll);
|
||||||
} else {
|
} else {
|
||||||
if (this.authSvc.loggedIn) {
|
if (this.authSvc.isAuth()) {
|
||||||
this.fetchAll.next(null);
|
this.fetchAll.next(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,9 @@ export class TalkgroupService {
|
||||||
}
|
}
|
||||||
|
|
||||||
setShare(share: Share | null) {
|
setShare(share: Share | null) {
|
||||||
this.fetchAll.next(share);
|
if (!this.authSvc.isAuth() && share !== null) {
|
||||||
|
this.fetchAll.next(share);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue