auth
CureNetMulti/pipeline/head Something is wrong with the build of this commit Details
CureNetMulti/pipeline/pr-dev There was a failure building this commit Details

This commit is contained in:
Sieciech 2021-08-03 16:16:56 +02:00
parent 239713c4f5
commit 6020575c5a
11 changed files with 112 additions and 29 deletions

View File

@ -6,12 +6,9 @@ use App\Entity\User;
use App\Traits\JsonResponseTrait; use App\Traits\JsonResponseTrait;
use App\Repository\UserRepository; use App\Repository\UserRepository;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
class AuthController extends AbstractController class AuthController extends AbstractController
@ -23,7 +20,7 @@ class AuthController extends AbstractController
} }
#[Route('/api/register', methods: ["POST"], name: 'register')] #[Route('/api/register', methods: ["POST"], name: 'register')]
public function register(Request $request, UserPasswordEncoderInterface $encoder) public function register(Request $request, UserPasswordHasherInterface $encoder)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$name = $request->get('name'); $name = $request->get('name');
@ -41,7 +38,7 @@ class AuthController extends AbstractController
} }
$user = new User(); $user = new User();
$user->setPassword($encoder->encodePassword($user, $password)); $user->setPassword($encoder->hashPassword($user, $password));
$user->setEmail($email); $user->setEmail($email);
$user->setName($name); $user->setName($name);
$user->setSurname($surname); $user->setSurname($surname);
@ -50,9 +47,20 @@ class AuthController extends AbstractController
return $this->created($user); return $this->created($user);
} }
#[Route('/api/login', methods: ["POST"], name: 'login')] #[Route('/api/login', methods: ['POST'], name: 'login')]
public function login(Request $request, JWTTokenManagerInterface $JWTManager) public function login(JWTTokenManagerInterface $JWTManager)
{ {
$user = new User();
return $this->ok(['token' => $JWTManager->create($user)]); return $this->ok(['token' => $JWTManager->create($user)]);
} }
#[Route('/api/user-check', methods: ['POST'])]
public function checkUser() {
$user = $this->getUser();
if (!$user) {
return $this->unauthorized([]);
}
$user->generateAvatar();
return $this->ok($user);
}
} }

View File

@ -6,13 +6,14 @@ use Doctrine\ORM\Mapping as ORM;
use App\Repository\UserRepository; use App\Repository\UserRepository;
use App\Entity\Abstraction\BaseEntity; use App\Entity\Abstraction\BaseEntity;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
/** /**
* @ORM\Entity(repositoryClass=UserRepository::class) * @ORM\Entity(repositoryClass=UserRepository::class)
* @ORM\Table(name="`user`") * @ORM\Table(name="`user`")
*/ */
class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUserInterface class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUserInterface, JWTUserInterface
{ {
protected array $hidden = ['password', 'salt', 'userIdentifier', 'username']; protected array $hidden = ['password', 'salt', 'userIdentifier', 'username'];
@ -64,6 +65,12 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
*/ */
private $state; private $state;
public static function createFromPayload($username, array $payload)
{
$user = new User();
return $user;
}
public function getId(): ?string public function getId(): ?string
{ {
return $this->id; return $this->id;
@ -219,4 +226,10 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
return $this; return $this;
} }
public function generateAvatar() {
if (!$this->avatar) {
$this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash';
}
}
} }

View File

@ -20,6 +20,10 @@ trait JsonResponseTrait {
return $this->response([ 'error' => 'Not acceptable', 'data' => $data], $code, $headers); return $this->response([ 'error' => 'Not acceptable', 'data' => $data], $code, $headers);
} }
protected function unauthorized($data, $code = Response::HTTP_UNAUTHORIZED, $headers = []) {
return $this->response([ 'error' => 'Unauthorized', 'data' => $data], $code, $headers);
}
protected function response($data, $code = Response::HTTP_OK, $headers = []) { protected function response($data, $code = Response::HTTP_OK, $headers = []) {
if ($data instanceof BaseEntity) { if ($data instanceof BaseEntity) {

View File

@ -34,10 +34,9 @@
</div> </div>
</ng-container> </ng-container>
</ng-container> </ng-container>
</div> </div>
<div> <div>
<div class="d-flex user-box"> <div class="d-flex user-box" *ngIf="user">
<div class="avatar" [style.background-image]="url(user.avatar)"></div> <div class="avatar" [style.background-image]="url(user.avatar)"></div>
<div class="d-flex align-items-center flex-grow-1 p-2">{{ user.name }} {{ user.surname }}</div> <div class="d-flex align-items-center flex-grow-1 p-2">{{ user.name }} {{ user.surname }}</div>
<div class="user-menu-container"> <div class="user-menu-container">
@ -66,7 +65,6 @@
</mat-menu> </mat-menu>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</mat-drawer> </mat-drawer>

View File

@ -7,12 +7,14 @@ import { ThemeService } from './modules/shared/services/theme/theme.service';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { AuthService } from './modules/auth/services/auth/auth.service'; import { AuthService } from './modules/auth/services/auth/auth.service';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { UserModel } from './modules/auth/models/user.model';
enum SidebarOpenEnum { enum SidebarOpenEnum {
Default, Default,
Open, Open,
Closed, Closed,
} }
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
@ -31,11 +33,7 @@ export class AppComponent {
themeControl = new FormControl(); themeControl = new FormControl();
langControl = new FormControl(); langControl = new FormControl();
appRoutes = appRoutes; appRoutes = appRoutes;
user = { user: UserModel;
name: 'Name',
surname: 'Surname',
avatar: 'https://www.gravatar.com/avatar/81b206a89f89d5b1123b87606075c6a8?s=514&d=robohash',
};
isSidebarHidden = false; isSidebarHidden = false;
dynamicToolbarComponents = []; dynamicToolbarComponents = [];
@ -43,13 +41,10 @@ export class AppComponent {
switch (this.sidebarOpen) { switch (this.sidebarOpen) {
case SidebarOpenEnum.Open: case SidebarOpenEnum.Open:
return true; return true;
break;
case SidebarOpenEnum.Closed: case SidebarOpenEnum.Closed:
return false; return false;
break;
default: default:
return this.defaultSidebarOpen; return this.defaultSidebarOpen;
break;
} }
} }
@ -65,6 +60,14 @@ export class AppComponent {
this.configureThemeEvents(); this.configureThemeEvents();
this.configureLanguageEvents(); this.configureLanguageEvents();
this.configureResizeEvents(); this.configureResizeEvents();
this.configureUserEvents();
}
configureUserEvents() {
this.user = this.authService.getUser();
this.authService.userChange.subscribe(user => {
this.user = user;
});
} }
configureSidebarEvents() { configureSidebarEvents() {

View File

@ -6,5 +6,4 @@
margin: 0px auto; margin: 0px auto;
margin-top: -150px; margin-top: -150px;
height: 200px; height: 200px;
border-radius: 6px;
} }

View File

@ -1,19 +1,47 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { BrowserStorageService } from 'src/app/modules/shared/services/browser-storage/browser-storage.service';
import { LoginModel } from '../../models/login.model'; import { LoginModel } from '../../models/login.model';
import { RegisterModel } from '../../models/register.model'; import { RegisterModel } from '../../models/register.model';
import { TokenResponse } from '../../models/token.response'; import { TokenResponse } from '../../models/token.response';
import { UserModel } from '../../models/user.model'; import { UserModel } from '../../models/user.model';
import { AuthTokenService } from '../../../shared/services/auth/auth-token.service'; import { AuthTokenService } from '../../../shared/services/auth/auth-token.service';
import { Router } from '@angular/router';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
private static updateAgent: any;
private user: UserModel;
public userChange = new Subject<UserModel>();
constructor( constructor(
private http: HttpClient, private http: HttpClient,
private authTokenService: AuthTokenService, private authTokenService: AuthTokenService,
private router: Router,
) { ) {
this.checkUser();
this.userChange.subscribe(user => {
this.user = user;
});
}
getUser(): UserModel {
return this.user;
}
checkUser() {
this.http.post<UserModel>('/api/user-check', {}).subscribe(user => {
this.userChange.next(user);
if (AuthService.updateAgent) {
clearTimeout(AuthService.updateAgent);
}
AuthService.updateAgent = setTimeout(() => {
this.checkUser();
}, 2000) as any;
}, () => {
this.logout();
});
} }
createAccount(data: RegisterModel): Observable<UserModel> { createAccount(data: RegisterModel): Observable<UserModel> {
@ -27,6 +55,7 @@ export class AuthService {
password: data.password, password: data.password,
}).subscribe(data => { }).subscribe(data => {
this.authTokenService.setToken(data.token); this.authTokenService.setToken(data.token);
this.checkUser();
out.next(data); out.next(data);
}); });
return out; return out;
@ -34,5 +63,6 @@ export class AuthService {
logout() { logout() {
this.authTokenService.removeToken(); this.authTokenService.removeToken();
this.router.navigate(['/auth']);
} }
} }

View File

@ -1,3 +1,10 @@
<div class="primary-background toolbar-background"></div>
<div class="content align-items-center justify-content-center">
<div class="col-11 col-lg-7 col-xl-5">
<mat-card>
<div class="m-3 p-3"> <div class="m-3 p-3">
{{ 'ERROR.PAGE_NOT_FOUND' | translate }} {{ 'ERROR.PAGE_NOT_FOUND' | translate }}
</div> </div>
</mat-card>
</div>
</div>

View File

@ -0,0 +1,10 @@
.primary-background{
background-color: var(--toolbar-background);
height: 100px;
}
.content{
margin: 0px auto;
margin-top: -100px;
height: 200px;
display: flex;
}

View File

@ -0,0 +1,9 @@
export class User {
id: number;
email: string;
name: string;
surname: string;
avatar: string;
country: string;
state: string;
}

View File

@ -4,6 +4,7 @@ import { NotFoundComponent } from './components/not-found/not-found.component';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpLoaderFactory } from 'src/app/app.module'; import { HttpLoaderFactory } from 'src/app/app.module';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { MaterialModule } from '../material/material.module';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -11,6 +12,7 @@ import { HttpClient } from '@angular/common/http';
], ],
imports: [ imports: [
CommonModule, CommonModule,
MaterialModule,
TranslateModule.forRoot({ TranslateModule.forRoot({
defaultLanguage: 'en', defaultLanguage: 'en',
loader: { loader: {