This commit is contained in:
William Nolin 2021-12-09 18:53:16 -05:00
parent 019b20fd02
commit 07b410d053
5 changed files with 101 additions and 53 deletions

View File

@ -10,6 +10,9 @@
"e2e": "ng e2e" "e2e": "ng e2e"
}, },
"private": true, "private": true,
"browser": {
"fs": false
},
"dependencies": { "dependencies": {
"@angular/animations": "~12.2.14", "@angular/animations": "~12.2.14",
"@angular/cdk": "^12.2.13", "@angular/cdk": "^12.2.13",
@ -21,10 +24,11 @@
"@angular/platform-browser": "~12.2.14", "@angular/platform-browser": "~12.2.14",
"@angular/platform-browser-dynamic": "~12.2.14", "@angular/platform-browser-dynamic": "~12.2.14",
"@angular/router": "~12.2.14", "@angular/router": "~12.2.14",
"@js-joda/core": "^4.3.1",
"@mdi/angular-material": "^6.5.95", "@mdi/angular-material": "^6.5.95",
"bootstrap": "^4.5.2", "bootstrap": "^4.5.2",
"copy-webpack-plugin": "^10.0.0", "copy-webpack-plugin": "^10.0.0",
"@js-joda/core": "^4.3.1", "jwt-decode": "^3.1.2",
"material-design-icons": "^3.0.1", "material-design-icons": "^3.0.1",
"ngx-material-file-input": "^2.1.1", "ngx-material-file-input": "^2.1.1",
"rxjs": "^7.4.0", "rxjs": "^7.4.0",

View File

@ -48,18 +48,17 @@ export class Login extends ErrorHandlingComponent {
} }
submit() { submit() {
this.subscribeAndNavigate(
this.accountService.login(this.userIdControl.value, this.passwordControl.value),
'/color'
)
// Does not use SubscribingComponent shortcut because backend doesn't return expected error type // Does not use SubscribingComponent shortcut because backend doesn't return expected error type
this.accountService.login(this.userIdControl.value, this.passwordControl.value) // this.accountService.login(this.userIdControl.value, this.passwordControl.value)
.pipe(take(1), takeUntil(this.destroy$)) // .pipe(take(1), takeUntil(this.destroy$))
.subscribe({ // .subscribe({
error: error => this.handleLoginError(error) // next: () => this.urlUtils.navigateTo('/color'),
}) // error: error => this.handleLoginError(error)
} // })
private handleLoginError(error) {
if (error.status === 403) {
this.alertService.pushError('Les identifiants entrés sont invalides')
}
} }
get controls(): { userId: FormControl, password: FormControl } { get controls(): { userId: FormControl, password: FormControl } {

View File

@ -1,14 +1,15 @@
import {Injectable, OnDestroy} from '@angular/core' import {Injectable, OnDestroy} from '@angular/core'
import {Observable, Subject} from 'rxjs' import {Observable, Subject} from 'rxjs'
import {take, takeUntil, tap} from 'rxjs/operators' import {take, takeUntil} from 'rxjs/operators'
import {AppState} from '../../shared/app-state' import {AppState} from '../../shared/app-state'
import {HttpClient, HttpResponse} from '@angular/common/http' import {HttpClient, HttpResponse} from '@angular/common/http'
import {environment} from '../../../../environments/environment' import {environment} from '../../../../environments/environment'
import {ApiService} from '../../shared/service/api.service' import {ApiService} from '../../shared/service/api.service'
import {User, Permission} from '../../shared/model/user' import {Permission} from '../../shared/model/user'
import {ErrorService} from '../../shared/service/error.service' import {ErrorService} from '../../shared/service/error.service'
import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component' import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component'
import {AlertService} from '../../shared/service/alert.service' import {AlertService} from '../../shared/service/alert.service'
import {JwtService} from "./jwt.service";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -20,6 +21,7 @@ export class AccountService implements OnDestroy {
private http: HttpClient, private http: HttpClient,
private api: ApiService, private api: ApiService,
private appState: AppState, private appState: AppState,
private jwtService: JwtService,
private errorService: ErrorService, private errorService: ErrorService,
private alertService: AlertService private alertService: AlertService
) { ) {
@ -37,47 +39,61 @@ export class AccountService implements OnDestroy {
checkAuthenticationStatus() { checkAuthenticationStatus() {
if (!this.appState.authenticatedUser) { if (!this.appState.authenticatedUser) {
// Try to get current default group user // Try to get current default group user
this.http.get<User>(`${environment.apiUrl}/user/current`, {withCredentials: true}) // this.http.get<User>(`${environment.apiUrl}/user/current`, {withCredentials: true})
.pipe( // .pipe(
take(1), // take(1),
takeUntil(this.destroy$), // takeUntil(this.destroy$),
).subscribe( // ).subscribe(
{ // {
next: user => this.appState.authenticatedUser = user, // next: user => this.appState.authenticatedUser = user,
error: err => { // error: err => {
if (err.status === 404 || err.status === 403) { // if (err.status === 404 || err.status === 403) {
console.warn('No default user is defined on this computer') // console.warn('No default user is defined on this computer')
} else { // } else {
this.errorService.handleError(err) // this.errorService.handleError(err)
} // }
} // }
}) // })
} }
} }
login(userId: number, password: string): Observable<any> { login(userId: number, password: string): Observable<any> {
globalLoadingWheel.show() const subject = new Subject<void>()
const request$ = this.http.post<any>(`${environment.apiUrl}/login`, {id: userId, password}, {
this.http.post<any>(`${environment.apiUrl}/login`, {id: userId, password}, {
withCredentials: true, withCredentials: true,
observe: 'response' as 'body' observe: 'response' as 'body'
}).pipe( }).pipe(
take(1), take(1),
takeUntil(this.destroy$) takeUntil(this.destroy$)
) ).subscribe({
next: (response: HttpResponse<void>) => {
this.loginUser(response)
request$.subscribe({ subject.next()
next: (response: HttpResponse<any>) => { subject.complete()
globalLoadingWheel.hide()
// TODO: Login user
}, },
error: error => { error: error => {
globalLoadingWheel.hide() if (error.status === 403) {
this.errorService.handleError(error) this.alertService.pushError('Les identifiants entrés sont invalides')
} else {
this.errorService.handleError(error)
}
subject.next()
subject.complete()
} }
}) })
return request$ return subject
}
private loginUser(response: HttpResponse<void>) {
const authorization = response.headers.get("Authorization")
const jwt = this.jwtService.parseJwt(authorization)
this.appState.authenticatedUser = jwt.user
this.appState.authenticationExpiration = jwt.exp
} }
loginOld(id: number, password: string, success: () => void) { loginOld(id: number, password: string, success: () => void) {
@ -129,18 +145,19 @@ export class AccountService implements OnDestroy {
} }
private setLoggedInUserFromApi() { private setLoggedInUserFromApi() {
this.api.get<User>('/user/current', true) // this.api.get<User>('/user/current', true)
.pipe( // .pipe(
take(1), // take(1),
takeUntil(this.destroy$) // takeUntil(this.destroy$)
) // )
.subscribe({ // .subscribe({
next: user => { // next: user => {
this.appState.authenticatedUser = user // this.appState.authenticatedUser = user
// At this point the loading wheel should be visible // At this point the loading wheel should be visible
globalLoadingWheel.hide() // globalLoadingWheel.hide()
}, // },
error: err => this.errorService.handleError(err) // error: err => this.errorService.handleError(err)
}) // })
console.warn("REMOVE THIS")
} }
} }

View File

@ -0,0 +1,25 @@
import {Injectable} from "@angular/core";
import {User} from "../../shared/model/user";
import jwtDecode from "jwt-decode";
import {parseJson} from "@angular/cli/utilities/json-file";
@Injectable({
providedIn: 'root'
})
export class JwtService {
parseJwt(jwt: string): CreJwt {
const decoded = jwtDecode(jwt) as any
return {
sub: decoded.sub,
exp: decoded.exp,
user: parseJson(decoded.user)
}
}
}
interface CreJwt {
readonly sub: string
readonly exp: number,
readonly user: User
}

View File

@ -2,6 +2,7 @@ import {Injectable} from '@angular/core'
import {User} from './model/user' import {User} from './model/user'
import {Subject} from 'rxjs' import {Subject} from 'rxjs'
import {Title} from '@angular/platform-browser' import {Title} from '@angular/platform-browser'
import jwtDecode from "jwt-decode";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -59,8 +60,10 @@ export class AppState {
set authenticatedUser(value: User) { set authenticatedUser(value: User) {
if (value === null) { if (value === null) {
console.log(1)
sessionStorage.removeItem(this.KEY_LOGGED_IN_USER) sessionStorage.removeItem(this.KEY_LOGGED_IN_USER)
} else { } else {
console.log(2)
sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value)) sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value))
} }
this.authenticatedUser$.next({ this.authenticatedUser$.next({