auth
This commit is contained in:
parent
239713c4f5
commit
6020575c5a
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -6,5 +6,4 @@
|
||||||
margin: 0px auto;
|
margin: 0px auto;
|
||||||
margin-top: -150px;
|
margin-top: -150px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
border-radius: 6px;
|
|
||||||
}
|
}
|
|
@ -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']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
.primary-background{
|
||||||
|
background-color: var(--toolbar-background);
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
margin: 0px auto;
|
||||||
|
margin-top: -100px;
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export class User {
|
||||||
|
id: number;
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
surname: string;
|
||||||
|
avatar: string;
|
||||||
|
country: string;
|
||||||
|
state: string;
|
||||||
|
}
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in New Issue