auth update

master
Константин 2023-12-11 13:46:19 +03:00
parent 8dd970f468
commit 5f7ee052b6
40 changed files with 455 additions and 542 deletions

View File

@ -5,20 +5,14 @@ import { AuthenticationService } from '@app/_services';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private router: Router, private authenticationService: AuthenticationService) {
constructor(private router: Router, private authService: AuthenticationService) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const oauthToken = this.authenticationService.oauthTokenValue;
if (oauthToken) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.authenticationService.popup('login');
//this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
if (this.authService.isLoggedIn) return true;
let extras = (state.url !== '/') ? {queryParams: {returnUrl: state.url}} : {};
this.authService.popup('login');
//this.router.navigate(['login'], extras).then();
return false;
}
}

View File

@ -7,20 +7,16 @@ import { AuthenticationService } from '@app/_services';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
constructor(private authService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const oauthToken = this.authenticationService.token.value;
const isLoggedIn = oauthToken && oauthToken.access_token;
const isApiUrl = request.url.startsWith(environment.apiUrl);
if (isLoggedIn && isApiUrl) {
request = request.clone({
setHeaders: {
Authorization: `${oauthToken.token_type} ${oauthToken.access_token}`
}
});
}
return next.handle(request);
const oauthToken = this.authService.token;
const isApiUrl = request.url.startsWith(environment.apiUrl);
if (this.authService.isLoggedIn && isApiUrl) {
request = request.clone({
setHeaders: {Authorization: `${oauthToken.token_type} ${oauthToken.access_token}`}
});
}
return next.handle(request);
}
}

View File

@ -0,0 +1,15 @@
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthenticationService } from '@app/_services';
@Injectable({ providedIn: 'root' })
export class NotAuthGuard implements CanActivate {
constructor(private router: Router, private authService: AuthenticationService) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (!this.authService.isLoggedIn) return true;
this.router.navigate(['/']).then();
return false;
}
}

View File

@ -23,7 +23,7 @@ export class AdministrationPageComponent {
}
ngOnInit() {
this.authService.user.subscribe(val => {
this.authService.userSubject.subscribe(val => {
this.makeTabs();
});
}

View File

@ -1,19 +1,20 @@
import {NgModule} from '@angular/core'
import {CommonModule} from '@angular/common'
import {RouterModule} from "@angular/router";
import {LoginComponent} from "@app/_modules/auth/login/login.component";
import {AuthFormLoginComponent} from "@app/_modules/auth/forms/login/auth-form-login.component";
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {ForgetComponent} from "@app/_modules/auth/forget/forget.component";
import {PasswordResetComponent} from "@app/_modules/auth/reset/password-reset.component";
import {SignupComponent} from "@app/_modules/auth/signup/signup.component";
import {AuthFormComponent} from "@app/_modules/auth/form/form.component";
import {AuthFormPasswordForgetComponent} from "@app/_modules/auth/forms/forget/auth-form-password-forget.component";
import {AuthFormPasswordResetComponent} from "@app/_modules/auth/forms/reset/auth-form-password-reset.component";
import {AuthFormSignupComponent} from "@app/_modules/auth/forms/signup/auth-form-signup.component";
import {AuthPageComponent} from "@app/_modules/auth/page/auth-page.component";
import {NotAuthGuard} from "@app/_helpers/not-auth.guard";
const routes = [
{path: 'login', component: AuthFormComponent, outlet: 'auth'},
{path: 'signup', component: AuthFormComponent, outlet: 'auth'},
{path: 'password/forget', component: AuthFormComponent, outlet: 'auth'},
{path: 'password/reset/:token/:email', component: PasswordResetComponent}
{path: 'login', component: AuthPageComponent, canActivate: [NotAuthGuard]},
{path: 'signup', component: AuthPageComponent, canActivate: [NotAuthGuard]},
{path: 'password/forget', component: AuthPageComponent, canActivate: [NotAuthGuard]},
{path: 'password/reset/:token/:email', component: AuthPageComponent, canActivate: [NotAuthGuard]}
];
@NgModule({
@ -22,17 +23,17 @@ const routes = [
FormsModule,
ReactiveFormsModule,
CommonModule,
RouterModule.forRoot(routes),
RouterModule.forRoot(routes)
],
exports: [
RouterModule,
],
declarations: [
AuthFormComponent,
LoginComponent,
SignupComponent,
ForgetComponent,
PasswordResetComponent,
AuthPageComponent,
AuthFormLoginComponent,
AuthFormSignupComponent,
AuthFormPasswordForgetComponent,
AuthFormPasswordResetComponent
],
})
export class AuthModule {}

View File

@ -1,24 +0,0 @@
<div class="popup">
<form [formGroup]="form" (submit)="onSubmit()">
<div class="header">
<h2>Восстановление пароля</h2>
<button type="button" class="close" (click)="close()"></button>
</div>
<div class="body" *ngIf="!success">
<div class="field" [class.invalid]="email.invalid && email.touched">
<label for="username">Электронная почта*</label>
<input id="username" formControlName="email" type="email" />
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="description">Если указанный адрес зарегистрирован, то на него будет выслан новый пароль</div>
</div>
<div class="body success" *ngIf="success">
<h3>Письмо с инструкциями было отправлено на указанный адрес.</h3>
<p>Пожалуйста, проверьте почту и выполните указанные в письме инструкции.</p>
</div>
<div class="footer">
<button type="button" class="btn secondary" (click)="login()">Авторизоваться</button>
<button *ngIf="!success" [disabled]="loading" type="submit" class="btn">Запросить</button>
</div>
</form>
</div>

View File

@ -1,5 +0,0 @@
.success {
h3, p {
margin: 0;
}
}

View File

@ -1,7 +0,0 @@
<div class="auth">
<div class="form">
<auth-login *ngIf="path==='login'"></auth-login>
<auth-signup *ngIf="path==='signup'"></auth-signup>
<auth-forget *ngIf="path==='password/forget'"></auth-forget>
</div>
</div>

View File

@ -1,26 +0,0 @@
.auth {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 24px;
background-color: rgba(62, 61, 64, 70%);
display: flex;
align-items: center;
z-index: 1000;
.form {
max-width: 520px;
width: 100%;
max-height: 632px;
height: 100%;
border-radius: 24px;
background-color: var(--white);
margin: 0 auto;
}
}
@media screen and (max-width: 600px) {
.auth {
padding: 0;
}
}

View File

@ -1,26 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Subscription} from "rxjs";
import {AuthenticationService} from "@app/_services";
@Component({
templateUrl: 'form.component.html',
styleUrls: ['form.component.scss']
})
export class AuthFormComponent implements OnInit {
public subscription: Subscription;
constructor(private authService: AuthenticationService, private route: ActivatedRoute) {
this.subscription = this.authService.user.subscribe(user => {
if (user) window.location.reload();
});
}
ngOnInit() {
}
get path() {
return this.route?.snapshot?.routeConfig?.path;
}
}

View File

@ -0,0 +1,20 @@
<h2>Восстановление пароля</h2>
<div class="body" *ngIf="!success">
<form [formGroup]="form" (submit)="onSubmit()">
<div class="field" [class.invalid]="email.invalid && email.touched">
<label for="username">Электронная почта*</label>
<input id="username" formControlName="email" type="email" />
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="description">Если указанный адрес зарегистрирован, то на него будет выслан новый пароль</div>
<div class="bottom">
<button type="button" class="btn secondary" routerLink="/login">Авторизоваться</button>
<button *ngIf="!success" [disabled]="loading" type="submit" class="btn">Запросить</button>
</div>
</form>
</div>
<div class="body success" *ngIf="success">
<h3>Письмо с инструкциями было отправлено на указанный адрес.</h3>
<p>Пожалуйста, проверьте почту и выполните указанные в письме инструкции.</p>
</div>

View File

@ -0,0 +1,10 @@
.success {
h3, p {
margin: 0;
}
}
.description {
font-size: 14px;
margin: 0 0 24px;
}

View File

@ -5,18 +5,17 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {AuthenticationService} from '@app/_services';
@Component({
selector: 'auth-forget',
templateUrl: 'forget.component.html',
styleUrls: ['forget.component.scss', '../login/login.component.scss']
selector: 'auth-form-password-forget',
templateUrl: 'auth-form-password-forget.component.html',
styleUrls: ['auth-form-password-forget.component.scss', '../forms.component.scss']
})
export class ForgetComponent implements OnInit {
export class AuthFormPasswordForgetComponent implements OnInit {
form: FormGroup;
loading = false;
success = false;
error = '';
constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private router: Router, private authenticationService: AuthenticationService) {
//if (this.authenticationService.oauthTokenValue) this.router.navigate(['']).then();
}
ngOnInit() {
@ -32,7 +31,7 @@ export class ForgetComponent implements OnInit {
return this.f?.email?.value;
}
onSubmit() {
onSubmit() {console.log(111)
if (this.form.invalid) return;
this.loading = true;
this.authenticationService.forget(this.email).subscribe(res => {
@ -48,12 +47,4 @@ export class ForgetComponent implements OnInit {
let trans = {'The given data was invalid.': 'Указанный адрес почты не найден'};
this.error = trans[error] || error;
}
login() {
this.authenticationService.popup('login');
}
close() {
this.authenticationService.popup(null);
}
}

View File

@ -0,0 +1,88 @@
h2 {
margin: 0 0 24px;
font-size: 24px;
font-weight: normal;
}
.field {
margin: 0 0 16px;
label {
font-size: 14px;
color: #666666;
line-height: 20px;
}
.checkbox {
display: flex;
flex-direction: row;
gap: 12px;
margin: 0 0 12px;
&:last-child {margin: 0;}
label {
font-size: 0.875rem;
color: #86898E;
a {
color: #F9B417;
}
}
input {
flex-shrink: 0;
width: 20px;
height: 20px;
margin: 0;
padding: 0;
}
}
}
.error {
margin: 0 0 16px;
font-size: 14px;
color: #D91519;
text-align: center;
}
.bar {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
flex-wrap: wrap;
row-gap: 18px;
.remember {
display: flex;
flex-direction: row;
align-items: center;
input {
width: 16px;
height: 16px;
margin-right: 8px;
border-radius: 2px;
border: 1px solid #86898E;
}
}
.forget {
margin-left: auto;
cursor: pointer;
}
}
.bottom {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
gap: 24px;
margin: 24px 0 0;
}
@media screen and (max-width: 600px) {
.bottom {
flex-direction: column-reverse;
button {
width: 100%;
}
}
}

View File

@ -0,0 +1,22 @@
<form [formGroup]="form" (submit)="onSubmit()">
<h2>Вход в систему</h2>
<div class="field" [class.invalid]="username.invalid && username.touched">
<label for="username">Логин</label>
<input id="username" formControlName="username" type="email" />
</div>
<div class="field" [class.invalid]="password.invalid && password.touched">
<label for="password">Пароль</label>
<input id="password" formControlName="password" type="password" autocomplete="off" />
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="bar">
<div class="remember">
<input id="remember" type="checkbox" />
<label for="remember">Запомнить меня</label>
</div>
<a class="forget" routerLink="/password/forget">Забыли пароль?</a>
</div>
<div class="bottom">
<button [disabled]="loading" type="submit" class="btn">Войти</button>
</div>
</form>

View File

@ -1,26 +1,19 @@
import {Component, OnInit} from '@angular/core';
import {Router, ActivatedRoute} from '@angular/router';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {AuthenticationService} from '@app/_services';
import {Subscription} from "rxjs";
@Component({
selector: 'auth-login',
templateUrl: 'login.component.html',
styleUrls: ['login.component.scss']
selector: 'auth-form-login',
templateUrl: 'auth-form-login.component.html',
styleUrls: ['auth-form-login.component.scss', '../forms.component.scss']
})
export class LoginComponent implements OnInit {
export class AuthFormLoginComponent implements OnInit {
form: FormGroup;
loading = false;
error = '';
subscription: Subscription;
public type: string = 'password';
constructor(private formBuilder: FormBuilder, private router: Router, private route: ActivatedRoute, private authenticationService: AuthenticationService) {
//this.subscription = this.authenticationService.user.subscribe(user => {
// if (user) this.router.navigate([this.route.snapshot.queryParamMap.get('returnUrl')?.split('(')[0] || '']).then();
//});
constructor(private formBuilder: FormBuilder, private router: Router, private route: ActivatedRoute, private authService: AuthenticationService) {
}
ngOnInit() {
@ -30,10 +23,6 @@ export class LoginComponent implements OnInit {
});
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
get f() {
return this.form.controls;
}
@ -47,8 +36,9 @@ export class LoginComponent implements OnInit {
onSubmit() {
if (this.form.invalid) return;
this.loading = true;
this.authenticationService.getToken(this.username, this.password).subscribe(res => {
this.authenticationService.saveToken(res);
this.authService.login(this.username, this.password).subscribe(res => {
this.authService.token = res;
this.router.navigate(['']).then();
}, error => {
this.setError(error.message);
this.loading = false;
@ -59,16 +49,4 @@ export class LoginComponent implements OnInit {
let trans = {'The user credentials were incorrect.': 'Имя пользователя или пароль указаны неверно.'};
this.error = trans[error] || error;
}
forget() {
this.authenticationService.popup(['password','forget']);
}
close() {
this.authenticationService.popup(null);
}
signup() {
this.authenticationService.popup('signup');
}
}

View File

@ -0,0 +1,17 @@
<form [formGroup]="form" (submit)="onSubmit()">
<h2>Сброс пароля</h2>
<div class="field password">
<label for="password">Укажите новый пароль</label>
<input id="password" formControlName="password" type="password" />
</div>
<div class="field confirmation">
<label for="confirmation">Новый пароль еще раз</label>
<input id="confirmation" formControlName="confirmation" type="password" />
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="bottom">
<button type="button" class="btn secondary" routerLink="/login">Авторизоваться</button>
<button [disabled]="loading" class="btn">Сохранить</button>
</div>
</form>

View File

@ -5,16 +5,16 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {AuthenticationService} from '@app/_services';
@Component({
templateUrl: 'password-reset.component.html',
styleUrls: ['password-reset.component.scss', '../login/login.component.scss']
selector: 'auth-form-password-reset',
templateUrl: 'auth-form-password-reset.component.html',
styleUrls: ['auth-form-password-reset.component.scss', '../forms.component.scss']
})
export class PasswordResetComponent implements OnInit {
export class AuthFormPasswordResetComponent implements OnInit {
form: FormGroup;
loading = false;
error = '';
constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private router: Router, private authenticationService: AuthenticationService) {
//if (this.authenticationService.oauthTokenValue) this.router.navigate(['']).then();
}
ngOnInit() {

View File

@ -0,0 +1,50 @@
<form [formGroup]="form" (submit)="onSubmit()">
<h2>Регистрация</h2>
<div class="body">
<div class="field" [class.invalid]="email.invalid && email.touched">
<label for="email">Электронная почта*</label>
<input id="email" formControlName="email" type="email" />
<!--p *ngIf="email.errors?.required">Поле обязательно для заполнения</p-->
<p *ngIf="email.errors?.email">Адрес почты указан не корректно</p>
<p *ngFor="let err of asyncErrors.email">{{err}}</p>
</div>
<div class="field" [class.invalid]="name.invalid && name.touched">
<label for="name">Фамилия, имя, отчество*</label>
<input id="name" formControlName="name" type="text" />
<!--p *ngIf="name.errors?.required">Поле обязательно для заполнения</p-->
</div>
<div class="field">
<label for="phone">Телефон</label>
<input id="phone" formControlName="phone" type="text" />
</div>
<div class="field" [class.invalid]="password.invalid && password.touched">
<label for="password">Пароль</label>
<input id="password" formControlName="password" type="password" />
<!--p *ngIf="password.errors?.required">Поле обязательно для заполнения</p-->
<p *ngFor="let err of asyncErrors.password">{{err}}</p>
</div>
<div class="field" [class.invalid]="confirmation.invalid && confirmation.touched">
<label for="confirmation">Подтверждение пароля*</label>
<input id="confirmation" formControlName="passwordConfirmation" type="password" />
<!--p *ngIf="confirmation.errors?.required">Поле обязательно для заполнения</p-->
</div>
<!--div class="field" [class.invalid]="agree.invalid || read.invalid">
<div class="checkbox">
<input type="checkbox" id="agree" formControlName="agree" />
<label for="agree">Согласен на обработку <a href="/src/assets/documents/privacy-policy.pdf" target="_blank">персональных данных</a></label>
</div>
<p *ngIf="agree.errors?.required && agree.touched">Необходимо поставить галочку</p>
<div class="checkbox">
<input type="checkbox" id="read" formControlName="read" />
<label for="read">С Политикой обработки <a href="/src/assets/documents/privacy-policy.pdf" target="_blank">персональных данных</a> ознакомлен</label>
</div>
<p *ngIf="read.errors?.required && read.touched">Необходимо поставить галочку</p>
</div-->
<div *ngIf="error" class="error">{{error}}</div>
</div>
<div class="bottom">
<button type="button" class="btn secondary" routerLink="/login">Авторизоваться</button>
<button type="submit" [disabled]="loading" class="btn">Зарегистрироваться</button>
</div>
</form>

View File

@ -6,21 +6,18 @@ import {AuthenticationService} from '@app/_services';
import {Subscription} from "rxjs";
@Component({
selector: 'auth-signup',
templateUrl: 'signup.component.html',
styleUrls: ['signup.component.scss', '../login/login.component.scss']
selector: 'auth-form-signup',
templateUrl: 'auth-form-signup.component.html',
styleUrls: ['auth-form-signup.component.scss', '../forms.component.scss']
})
export class SignupComponent implements OnInit {
export class AuthFormSignupComponent implements OnInit {
form: FormGroup;
loading = false;
error = '';
asyncErrors: any = {};
subscription: Subscription;
constructor(private formBuilder: FormBuilder, private router: Router, private route: ActivatedRoute, private authenticationService: AuthenticationService) {
//this.subscription = this.authenticationService.user.subscribe(user => {
// if (user) this.router.navigate([this.route.snapshot.queryParamMap.get('returnUrl')?.split('(')[0] || 'applications']).then();
//});
constructor(private formBuilder: FormBuilder, private router: Router, private route: ActivatedRoute, private authService: AuthenticationService) {
}
ngOnInit() {
@ -29,12 +26,13 @@ export class SignupComponent implements OnInit {
name: ['', Validators.required],
phone: [''],
password: ['', Validators.required],
passwordConfirmation: ['', Validators.required]
passwordConfirmation: ['', Validators.required],
//agree: [null, Validators.requiredTrue],
//read: [null, Validators.requiredTrue]
});
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
get f() {
@ -52,15 +50,20 @@ export class SignupComponent implements OnInit {
get confirmation() {
return this.f.passwordConfirmation;
}
get agree() {
return this.f.agree;
}
get read() {
return this.f.read;
}
onSubmit() {
this.form.markAllAsTouched();
if (this.form.invalid) return;
this.loading = true;
this.authenticationService.signup(this.form.value).subscribe(res => {
this.authenticationService.getToken(this.email.value, this.password.value).subscribe(res => {
this.authenticationService.saveToken(res);
this.close();
this.authService.signup(this.form.value).subscribe(res => {
this.authService.login(this.email.value, this.password.value).subscribe(res => {
this.authService.token = res;
});
}, error => {
this.setError(error);
@ -76,12 +79,4 @@ export class SignupComponent implements OnInit {
let trans = {'The given data was invalid.': 'Проверьте правильность заполнения формы'};
this.error = trans[error.message] || error.message;
}
close() {
this.authenticationService.popup(null);
}
login() {
this.authenticationService.popup('login');
}
}

View File

@ -1,31 +0,0 @@
<div class="popup">
<form [formGroup]="form" (submit)="onSubmit()">
<div class="header">
<h2>Вход</h2>
<button type="button" class="close" (click)="close()"></button>
</div>
<div class="body">
<div class="field" [class.invalid]="username.invalid && username.touched">
<label for="username">Логин</label>
<input id="username" formControlName="username" type="email" />
</div>
<div class="field" [class.invalid]="password.invalid && password.touched">
<label for="password">Пароль</label>
<input id="password" formControlName="password" [type]="type" autocomplete="off" />
<div class="eye {{type==='password'?'show':'hide'}}" (click)="type=type==='password'?'text':'password'"></div>
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="bar">
<div class="remember">
<input id="remember" type="checkbox" class="checkbox" />
<label for="remember">Запомнить меня</label>
</div>
<div class="forget" (click)="forget()">Забыли пароль?</div>
</div>
</div>
<div class="footer">
<!-- <button type="button" class="btn secondary" (click)="signup()">Зарегистрироваться</button> -->
<button [disabled]="loading" type="submit" class="btn">Войти</button>
</div>
</form>
</div>

View File

@ -1,162 +0,0 @@
.popup {
display: flex;
flex-direction: column;
height: 100%;
background-color: #ffffff;
border-radius: 8px;
font-size: 20px;
form {
display: flex;
flex-direction: column;
height: 100%;
.header {
flex-grow: 0;
border-radius: 24px 24px 0 0;
padding: 14px 24px;
display: flex;
flex-direction: row;
align-items: center;
border-bottom: 1px solid var(--second-dis);
h2 {
margin: 0;
font-family: PT Sans Narrow;
font-size: 36px;
font-style: normal;
font-weight: 700;
line-height: 44px; /* 122.222% */
letter-spacing: 0.36px;
color: var(--second-act);
}
.close {
width: 24px;
height: 24px;
margin-left: auto;
padding: 0;
border: none;
border-radius: 0;
background: transparent url(/assets/images/icons/close_24dp.svg) 50% 50% no-repeat;
}
}
.body {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
overflow: auto;
padding: 32px 24px;
-webkit-overflow-scrolling: touch;
row-gap: 24px;
.field {
display: flex;
flex-direction: column;
row-gap: 4px;
position: relative;
label {
font-style: normal;
font-weight: 400;
font-size: 20px;
line-height: normal;
}
input{
&:autofill {
background: #A1CAE5;
}
&:hover{
border-color: var(--second);
outline: none;
}
&:focus, &:focus-visible {
border-color: var(--prime);
outline: none;
}
&:disabled{
border-color: #EDEDED;
outline: none;
}
}
.eye {
position: absolute;
bottom: 8px;
right: 12px;
width: 24px;
height: 24px;
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
&.show {background-image: url("~src/assets/images/icons/visibility_on_24dp.svg");}
&.hide {background-image: url("~src/assets/images/icons/visibility_off_24dp.svg");}
}
}
.error {
color: red;
}
.bar {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
flex-wrap: wrap;
row-gap: 18px;
.remember {
display: flex;
flex-direction: row;
align-items: center;
input {
width: 16px;
height: 16px;
margin-right: 8px;
border-radius: 2px;
border: 1px solid #86898E;
}
}
.forget {
margin-left: auto;
cursor: pointer;
}
}
}
.footer {
display: flex;
flex-grow: 0;
border-top: 1px solid var(--second-dis);
// border-radius: 0 0 24px 24px;
padding: 16px 24px;
justify-content: flex-end;
gap: 24px;
flex-wrap: wrap;
}
}
}
@media screen and (max-width: 1330px) {
.authentication {
flex-direction: column;
justify-content: center;
.logo {
width: 100%;
height: 76px;
margin-bottom: 50px;
background-color: transparent;
background-size: contain;
}
.block {
width: 100%;
}
}
}
@media screen and (max-width: 600px) {
.popup {
form {
.header, .footer {
border-radius: 0;
}
.footer {
.btn {
width: 100%;
}
}
}
}
}

View File

@ -0,0 +1,17 @@
<div class="authentication">
<div class="logo">
<div class="center">
<img src="assets/images/logo.svg" /><br />
<p>Реестр средств измерений</p>
</div>
</div>
<div class="form">
<div class="center" [ngSwitch]="url">
<auth-form-login *ngSwitchCase="'login'"></auth-form-login>
<auth-form-signup *ngSwitchCase="'signup'"></auth-form-signup>
<auth-form-password-forget *ngSwitchCase="'password/forget'"></auth-form-password-forget>
<auth-form-password-reset *ngSwitchCase="'password/reset'"></auth-form-password-reset>
<p *ngSwitchDefault>{{url}} is undefined</p>
</div>
</div>
</div>

View File

@ -0,0 +1,46 @@
.authentication {
display: flex;
flex-direction: row;
width: 100%;
height: 100vh;
.logo {
display: flex;
width: 50%;
flex-shrink: 0;
height: 100%;
border-right: #E0E0E0 solid 1px;
text-align: center;
color: #0071BB;
}
.form {
display: flex;
flex-grow: 1;
padding: 24px;
}
.center {
width: 100%;
max-width: 416px;
margin: auto;
}
}
@media screen and (max-width: 959px) {
.authentication {
flex-direction: column;
justify-content: center;
.logo {
width: 100%;
height: auto;
border-right: none;
}
.form {
flex-grow: 0;
}
::ng-deep h2 {
text-align: center;
}
}
}

View File

@ -0,0 +1,21 @@
import {Component, OnInit} from '@angular/core';
import {Router} from "@angular/router";
@Component({
selector: 'auth-page',
templateUrl: 'auth-page.component.html',
styleUrls: ['auth-page.component.scss']
})
export class AuthPageComponent implements OnInit {
constructor(private router: Router) {
}
get url() {
return this.router.url.split('?')[0].split('(')[0].split('/').slice(1, 3).join('/');
}
ngOnInit() {
}
}

View File

@ -1,24 +0,0 @@
<div class="authentication">
<div class="logo"></div>
<div class="block">
<form [formGroup]="form" (submit)="onSubmit()">
<div class="form-title">Сброс пароля</div>
<div class="field password">
<label for="password">Укажите новый пароль</label>
<input id="password" formControlName="password" type="password" />
</div>
<div class="field confirmation">
<label for="confirmation">Новый пароль еще раз</label>
<input id="confirmation" formControlName="confirmation" type="password" />
</div>
<div *ngIf="error" class="error">{{error}}</div>
<div class="bar">
<div class="forget"><a routerLink="/login">Авторизация</a></div>
</div>
<div class="submit">
<button [disabled]="loading" class="btn">Сохранить</button>
</div>
</form>
</div>
</div>

View File

@ -1,43 +0,0 @@
<div class="popup">
<form [formGroup]="form" (submit)="onSubmit()">
<div class="header">
<h2>Регистрация</h2>
<button type="button" class="close" (click)="close()"></button>
</div>
<div class="body">
<div class="field" [class.invalid]="email.invalid && email.touched">
<label for="email">Электронная почта*</label>
<input id="email" formControlName="email" type="email" />
<!--p *ngIf="email.errors?.required">Поле обязательно для заполнения</p-->
<p *ngIf="email.errors?.email">Адрес почты указан не корректно</p>
<p *ngFor="let err of asyncErrors.email">{{err}}</p>
</div>
<div class="field" [class.invalid]="name.invalid && name.touched">
<label for="name">Фамилия, имя, отчество*</label>
<input id="name" formControlName="name" type="text" />
<!--p *ngIf="name.errors?.required">Поле обязательно для заполнения</p-->
</div>
<div class="field">
<label for="phone">Телефон</label>
<input id="phone" formControlName="phone" type="text" />
</div>
<div class="field" [class.invalid]="password.invalid && password.touched">
<label for="password">Пароль</label>
<input id="password" formControlName="password" type="password" />
<!--p *ngIf="password.errors?.required">Поле обязательно для заполнения</p-->
<p *ngFor="let err of asyncErrors.password">{{err}}</p>
</div>
<div class="field" [class.invalid]="confirmation.invalid && confirmation.touched">
<label for="confirmation">Подтверждение пароля*</label>
<input id="confirmation" formControlName="passwordConfirmation" type="password" />
<!--p *ngIf="confirmation.errors?.required">Поле обязательно для заполнения</p-->
</div>
<div *ngIf="error" class="error">{{error}}</div>
</div>
<div class="footer">
<button type="button" class="btn secondary" (click)="login()">Авторизоваться</button>
<button type="submit" [disabled]="loading" class="btn">Зарегистрироваться</button>
</div>
</form>
</div>

View File

@ -20,7 +20,7 @@
<a href="#">
<img src="assets/images/icons/zen_black_28x28.svg" alt="">
</a>
</div>
</div>
</div>
<div class="menu">
<div>
@ -46,7 +46,7 @@
<div>
<a href="/glavnaia/novosti">Новости</a>
</div>
<div *ngIf="!user">
<div *ngIf="!isLoggedIn">
<a (click)="login()">Вход в личный кабинет</a>
</div>
</div>

View File

@ -8,19 +8,18 @@ import {Subscription} from "rxjs";
styleUrls: ['footer.component.scss']
})
export class FooterComponent {
subscription: Subscription;
public user: any;
constructor(public authenticationService: AuthenticationService) {
this.subscription = this.authenticationService.user.subscribe(user => {
this.user = user;
});
constructor(public authService: AuthenticationService) {
}
get isLoggedIn() {
return this.authService.isLoggedIn;
}
ngOnInit() {
}
login() {
this.authenticationService.popup('login');
this.authService.popup('login');
}
}

View File

@ -11,20 +11,16 @@ import { PagesService } from '@app/_services/pages.service';
styleUrls: ['header-user-bar.component.scss']
})
export class HeaderUserBarComponent {
public user: any;
public menuItems = <any>[];
public ddHidden = true;
subscriptionUser: Subscription;
constructor(
public authService: AuthenticationService,
private router: Router,
private pagesService: PagesService) {
this.subscriptionUser = this.authService.user.subscribe(user => {
this.user = user;
});
constructor(public authService: AuthenticationService, private router: Router, private pagesService: PagesService) {
}
get user() {
return this.authService.user;
}
get avatar() {
return this.user?.avatar?.data;
}
@ -36,10 +32,6 @@ export class HeaderUserBarComponent {
}
ngOnDestroy() {
this.subscriptionUser?.unsubscribe();
}
close() {
setTimeout(() => {

View File

@ -7,29 +7,26 @@ import {Subscription} from "rxjs";
styleUrls: ['user-profile.component.scss']
})
export class UserProfileComponent {
public user: any;
inited = false;
userSubscription: Subscription;
controlsSubscription: Subscription;
constructor(private listsService: ListsService, private formsService: FormsService, private authService: AuthenticationService) {
this.userSubscription = this.authService.user.subscribe(user => {
this.user = user;
});
}
get user() {
return this.authService.user;
}
get avatar() {
return this.user?.avatar?.data;
}
ngOnInit() {
this.controlsSubscription = this.listsService.controls().subscribe(res => {
this.inited ? this.authService.checkUser() : this.inited = true;
this.inited ? this.authService.getCurrentUser() : this.inited = true;
});
}
ngOnDestroy() {
this.userSubscription?.unsubscribe();
this.controlsSubscription?.unsubscribe();
}

View File

@ -5,22 +5,44 @@ import {Router} from "@angular/router";
import {environment} from '@environments/environment';
import {OauthToken, User} from '@app/_models';
import {UsersService} from "@app/_services/users.service";
@Injectable({providedIn: 'root'})
export class AuthenticationService {
public token: BehaviorSubject<OauthToken>;
public user: BehaviorSubject<User>;
public tokenSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('oauthToken')));
public userSubject = new BehaviorSubject(null);
constructor(private http: HttpClient, private router: Router) {
this.token = new BehaviorSubject<OauthToken>(JSON.parse(localStorage.getItem('oauthToken')));
this.user = new BehaviorSubject<any>(null);
constructor(private http: HttpClient, private router: Router, private usersService: UsersService) {
}
get oauthTokenValue() {
return this.token.value;
get token(): OauthToken {
return this.tokenSubject.value;
}
set token(value: OauthToken) {
this.tokenSubject.next(value);
if (value) {
localStorage.setItem('oauthToken', JSON.stringify(value));
this.getCurrentUser();
} else {
localStorage.removeItem('oauthToken');
this.user = null;
}
}
get user(): User {
return this.userSubject.value;
}
set user(value: User) {
this.userSubject.next(value);
}
get isLoggedIn(): boolean {
return !!this.token?.access_token;
}
public get privileges() {
return this.user.value?.privileges;
return this.user?.privileges;
}
get isSuperAdmin() {
return this.privileges?.superAdmin;
@ -40,43 +62,33 @@ export class AuthenticationService {
signup(data: any): Observable<any> {
return this.http.post(`${environment.apiUrl}/api/signup`, data);
}
getToken(username: string, password: string): Observable<any> {
login(username: string, password: string): Observable<any> {
let data = {grant_type: 'password', client_id: environment.clientId, client_secret: environment.clientSecret, username: username, password: password};
return this.http.post(`${environment.apiUrl}/oauth/token`, data);
}
saveToken(token: OauthToken) {
localStorage.setItem('oauthToken', JSON.stringify(token));
this.token.next(token);
this.checkUser();
}
checkUser(params?: any) {
if (this.token.value) {
if (!params) params = {include: 'avatar,privileges'};
this.http.get(`${environment.apiUrl}/api/me`, {params: params}).subscribe((res: any) => {
this.user.next(res?.data);
});
}
}
logout() {
localStorage.removeItem('oauthToken');
this.token.next(null);
this.user.next(null);
}
forget(email: string): Observable<any> {
return this.http.post(`${environment.apiUrl}/api/passwords/reset`, {email});
}
restore(data: any): Observable<any> {
return this.http.put(`${environment.apiUrl}/api/passwords/reset`, data);
}
getCurrentUser(params?: any) {
if (this.isLoggedIn) this.usersService.me(params).subscribe(res => {
this.user = res.data;
});
}
logout() {
this.token = null;
}
popup(path: any) {
this.router.navigate([ {outlets: {auth: path}}], {skipLocationChange: true}).then();
this.router.navigate([path]).then();
//this.router.navigate([ {outlets: {auth: path}}], {skipLocationChange: true}).then();
}
}

View File

@ -6,5 +6,5 @@ export * from './forms.service';
export * from './lists.service';
export * from './notification.service';
export * from './objects.service';
export * from './user.service';
export * from './users.service';
export * from './utility.service';

View File

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '@environments/environment';
import {Observable} from "rxjs";
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {
}
me(params?: {}): Observable<any> {
return this.http.get(`${environment.apiUrl}/api/me`, {params: params});
}
}

View File

@ -0,0 +1,16 @@
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {environment} from '@environments/environment';
import {Observable} from "rxjs";
@Injectable({ providedIn: 'root' })
export class UsersService {
constructor(private http: HttpClient) {
}
me(params: any): Observable<any> {
if (!params) params = {include: 'avatar,membership.company,roles,privileges'};
return this.http.get<any>(`${environment.apiUrl}/api/me`, {params: params});
}
}

View File

@ -12,7 +12,7 @@ export class AppComponent {
public subscription: Subscription;
constructor(private authService: AuthenticationService, private pagesService: PagesService, private titleService: Title, private metaService: Meta) {
authService.checkUser();
authService.getCurrentUser();
this.subscription = this.pagesService.metaSubject.subscribe(data => {
this.applyMetaData(data);
});

View File

@ -6,7 +6,7 @@ export const environment = {
production: false,
apiUrl: 'http://api.nircms.lc',
clientId: 2,
clientSecret: 'v49Z7dwUb1cobcTIJ5JQVJBzOFcNyJMzMmiDspUm',
clientSecret: 'gVk3jjKq6rWWM52025xgXlw2XGW1UACowyMIyhRR',
project: null,
defaultLocale: 'ru'
};