diff --git a/src/api/v1/authApiService.ts b/src/api/v1/authApiService.ts index c8054a4..894d95b 100644 --- a/src/api/v1/authApiService.ts +++ b/src/api/v1/authApiService.ts @@ -7,6 +7,7 @@ import {AvailableOAuthProvidersResponse} from "@api/v1/availableProvidersRespons import {OAuthProvider} from "@model/oAuthProvider"; import {TwoFactorAuthentication} from "@model/twoFactorAuthentication"; import {TwoFactorAuthRequest} from "@api/v1/twoFactorAuthRequest"; +import {OAuthAction} from "@model/oAuthAction"; export interface OAuthProviderData extends AvailableOAuthProvidersResponse { icon: string; @@ -83,9 +84,10 @@ export default class AuthApiService extends ApiService { } } - public availableProviders(): Observable { + public availableProviders(callback: string): Observable { let request = this.createRequestBuilder() .setEndpoint('AvailableProviders') + .setQueryParams({callback: callback}) .setWithCredentials() .build; @@ -97,4 +99,21 @@ export default class AuthApiService extends ApiService { }) as OAuthProviderData); })); } + + private handleTokenRequest(token: string, action: OAuthAction) { + return this.createRequestBuilder() + .setEndpoint('HandleToken') + .setQueryParams({token: token, action: action}) + .setWithCredentials() + .build; + } + + public loginOAuth(token: string) { + return this.get(this.handleTokenRequest(token, OAuthAction.Login)); + } + + public linkAccount(token: string): Observable { + const request = this.handleTokenRequest(token, OAuthAction.Bind); + return this.addAuth(request).get(request); + } } diff --git a/src/pages/login/login.component.html b/src/pages/login/login.component.html index 51f45ab..61a8dfc 100644 --- a/src/pages/login/login.component.html +++ b/src/pages/login/login.component.html @@ -1,36 +1,53 @@ -

Вход в систему

- - Имя пользователя/email - + @if (!requiresTwoFactorAuth) { + + Имя пользователя/email + - @if (loginForm.get('user')?.hasError('required')) { - - Имя пользователя или email является обязательным - - } + @if (loginForm.get('user')?.hasError('required')) { + + Имя пользователя или email является обязательным + + } - @if (loginForm.get('user')?.hasError('minlength')) { - - Количество символов должно быть не менее 4 - - } - + @if (loginForm.get('user')?.hasError('minlength')) { + + Количество символов должно быть не менее 4 + + } + - + + } @else { + + Код 2FA + + @if (loginForm.get('twoFactorCode')?.hasError('required')) { + + Код 2FA обязателен. + + } + + } - + @if (!requiresTwoFactorAuth) { + + } {{ errorText }} @@ -42,7 +59,7 @@ } @else { diff --git a/src/pages/login/login.component.ts b/src/pages/login/login.component.ts index 209b064..b0cb8a7 100644 --- a/src/pages/login/login.component.ts +++ b/src/pages/login/login.component.ts @@ -5,7 +5,7 @@ import {MatInput} from "@angular/material/input"; import {MatTooltip} from "@angular/material/tooltip"; import {MatButton} from "@angular/material/button"; import {MatCard} from "@angular/material/card"; -import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; +import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; import {FocusNextDirective} from "@/directives/focus-next.directive"; import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component"; import AuthApiService from "@api/v1/authApiService"; @@ -40,6 +40,7 @@ export class LoginComponent { protected loaderActive: boolean = false; protected loginButtonIsDisable: boolean = true; protected errorText: string = ''; + protected requiresTwoFactorAuth: boolean = false; constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private router: Router) { this.auth.getRole() @@ -69,6 +70,22 @@ export class LoginComponent { }); } + private updateTwoFactorValidation(data: TwoFactorAuthentication) { + if (data === TwoFactorAuthentication.None) { + this.router.navigate(['admin']).then(); + return; + } + + this.requiresTwoFactorAuth = true; + this.loginForm.addControl( + 'twoFactorCode', + new FormControl('', Validators.required) + ); + this.loginForm.removeControl('user'); + this.loginForm.removeControl('password'); + this.loginButtonIsDisable = !this.loginForm.valid; + } + protected login() { this.loaderActive = true; @@ -85,11 +102,31 @@ export class LoginComponent { .subscribe(x => { this.loaderActive = false; this.errorText = ''; - - if (x == TwoFactorAuthentication.None) - this.router.navigate(['admin']).then(); - else - this.router.navigate(['two-factor']).then(); + this.updateTwoFactorValidation(x); }); } + + protected login2Fa() { + this.loaderActive = true; + + this.auth.twoFactorAuth({ + code: this.loginForm.get('twoFactorCode')?.value, + method: TwoFactorAuthentication.TotpRequired + }) + .pipe(catchError(error => { + this.loaderActive = false; + this.errorText = error.error.detail; + this.loginButtonIsDisable = true; + throw error; + })) + .subscribe(_ => { + this.loaderActive = false; + this.errorText = ''; + this.router.navigate(['admin']).then(); + }); + } + + protected loginOAuth(result: TwoFactorAuthentication) { + this.updateTwoFactorValidation(result); + } }