Add disconnection component.

This commit is contained in:
2019-09-06 22:22:48 +02:00
parent 6a68a329c2
commit 78701a4950
13 changed files with 111 additions and 29 deletions

View File

@@ -1,6 +1,8 @@
package org.cerberus.controllers; package org.cerberus.controllers;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.SignUpDTO; import org.cerberus.entities.dto.SignUpDTO;
import org.cerberus.entities.dto.View;
import org.cerberus.entities.persistence.User; import org.cerberus.entities.persistence.User;
import org.cerberus.services.UserService; import org.cerberus.services.UserService;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -24,9 +26,9 @@ public class UserController {
} }
@PostMapping("/login") @PostMapping("/login")
@ResponseStatus(NO_CONTENT) @JsonView({View.UserDTO.class})
public void login(@RequestBody User user) { public User login(@RequestBody User user) {
service.authenticate(user); return service.authenticate(user);
} }
@GetMapping("/disconnection") @GetMapping("/disconnection")

View File

@@ -4,4 +4,5 @@ public final class View {
private View() {} private View() {}
public interface ApplicationDTO {} public interface ApplicationDTO {}
public interface ConfigurationFileDTO {} public interface ConfigurationFileDTO {}
public interface UserDTO {}
} }

View File

@@ -1,5 +1,7 @@
package org.cerberus.entities.persistence; package org.cerberus.entities.persistence;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.hibernate.annotations.Generated; import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime; import org.hibernate.annotations.GenerationTime;
import org.hibernate.annotations.Proxy; import org.hibernate.annotations.Proxy;
@@ -14,22 +16,25 @@ import java.util.UUID;
@Proxy(lazy = false) @Proxy(lazy = false)
public class User { public class User {
@Id @Id
@JsonView({View.UserDTO.class})
private UUID id; private UUID id;
@Column(nullable = false) @Column(nullable = false)
@JsonView({View.UserDTO.class})
private String name; private String name;
@Column(nullable = false) @Column(nullable = false)
@JsonView({View.UserDTO.class})
private String email; private String email;
@Column(nullable = false) @Column(nullable = false)
private String password; private String password;
@Column(nullable = false) @Column(nullable = false)
@JsonView({View.UserDTO.class})
private Boolean isAdmin = false; private Boolean isAdmin = false;
@Column(nullable = false) @Column(nullable = false)
@Generated(GenerationTime.ALWAYS)
private LocalDate inscriptionDate; private LocalDate inscriptionDate;
@OneToMany(mappedBy = "user") @OneToMany(mappedBy = "user")

View File

@@ -37,7 +37,7 @@ public class UserService {
this.repository = repository; this.repository = repository;
} }
public void authenticate(User user) { public User authenticate(User user) {
User authenticatedUser = checkCredentials(user.getEmail(), user.getPassword()); User authenticatedUser = checkCredentials(user.getEmail(), user.getPassword());
authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken( authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(
@@ -45,6 +45,8 @@ public class UserService {
user.getPassword(), user.getPassword(),
fetchGrantedAuthorities(authenticatedUser) fetchGrantedAuthorities(authenticatedUser)
)); ));
return authenticatedUser;
} }
User checkCredentials(String email, String password) { User checkCredentials(String email, String password) {

View File

@@ -1,3 +1,4 @@
import { DisconnectionComponent } from './disconnection/disconnection.component';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component'; import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
@@ -5,6 +6,7 @@ import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [ const routes: Routes = [
{ path: 'serviceUnavailable', component: ServiceUnavailableComponent }, { path: 'serviceUnavailable', component: ServiceUnavailableComponent },
{ path: 'disconnection', component: DisconnectionComponent },
{ path: '', component: AppComponent } { path: '', component: AppComponent }
]; ];

View File

@@ -15,6 +15,7 @@ import { NotificationElement } from './core/notifications/notification-element/n
import { NotificationsComponent } from './core/notifications/notifications.component'; import { NotificationsComponent } from './core/notifications/notifications.component';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component'; import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component';
import { DisconnectionComponent } from './disconnection/disconnection.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -24,7 +25,8 @@ import { ServiceUnavailableComponent } from './service-unavailable/service-unava
LoginComponent, LoginComponent,
NotificationElement, NotificationElement,
NotificationsComponent, NotificationsComponent,
ServiceUnavailableComponent ServiceUnavailableComponent,
DisconnectionComponent
], ],
imports: [ imports: [
AppRoutingModule, AppRoutingModule,
@@ -35,11 +37,7 @@ import { ServiceUnavailableComponent } from './service-unavailable/service-unava
], ],
providers: [ providers: [
UserService, UserService,
{ { provide: HTTP_INTERCEPTORS, useClass: ServiceUnavailableInterceptor, multi: true }
provide: HTTP_INTERCEPTORS,
useClass: ServiceUnavailableInterceptor,
multi: true
}
], ],
bootstrap: [ bootstrap: [
AppComponent AppComponent

View File

@@ -0,0 +1,35 @@
import { Injectable } from '@angular/core';
import { User } from '../entities';
const PARAM_USER = 'user';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor() {}
public setAuthenticated(user: User): void {
this.setUser(user);
}
public setAnonymous(): void {
localStorage.clear();
}
public isAuthenticated(): boolean {
return this.getUser() != null;
}
public isAdmin(): boolean {
return false;
}
private setUser(user: User): void {
localStorage.setItem(PARAM_USER, JSON.stringify(user));
}
public getUser(): User {
return JSON.parse(localStorage.getItem(PARAM_USER));
}
}

View File

@@ -1,3 +1,4 @@
import { AuthService } from './auth.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
@@ -11,8 +12,8 @@ export class UserService {
private httpClient: HttpClient private httpClient: HttpClient
) {} ) {}
login(user: User): Observable<void> { login(user: User): Observable<User> {
return this.httpClient.post<void>(`/api/users/login`, user); return this.httpClient.post<User>(`/api/users/login`, user);
} }
disconnection(): Observable<void> { disconnection(): Observable<void> {

View File

@@ -0,0 +1,29 @@
import { Router } from '@angular/router';
import { AuthService } from './../core/services/auth.service';
import { UserService } from './../core/services/user.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-disconnection',
template: ''
})
export class DisconnectionComponent implements OnInit {
content = 'Déconnexion...';
constructor(
private authService: AuthService,
private router: Router,
private userService: UserService
) {}
ngOnInit(): void {
this.userService.disconnection().subscribe(() => {
this.authService.setAnonymous();
}, error => {
console.error('Error during disconnection: ', error);
this.content = 'Une erreur est survenue lors de la déconnexion.';
}, () => {
this.router.navigate(['/']);
});
}
}

View File

@@ -11,10 +11,14 @@
</a> </a>
</span> </span>
<span id="right-area"> <span id="right-area">
<button mdbBtn class="flat rounded-pill" (click)="loginForm.show()" mdbWavesEffect> <button mdbBtn class="flat rounded-pill" (click)="loginForm.show()" *ngIf="!isAuthenticated()" mdbWavesEffect>
<i class="fa fa-sign-in-alt"></i> <i class="fa fa-sign-in-alt"></i>
Connexion Connexion
</button> </button>
<a [routerLink]="['/disconnection']" mdbBtn id="disconnection-btn" class="flat rounded-pill" *ngIf="isAuthenticated()" mdbWavesEffect>
<i class="fa fa-sign-out-alt"></i>
Déconnexion
</a>
</span> </span>
</header> </header>
<app-login #loginForm></app-login> <app-login #loginForm></app-login>

View File

@@ -35,10 +35,14 @@ header {
top: 5px; top: 5px;
right: 15px; right: 15px;
button { .rounded-pill {
padding-right: 1.14rem; padding-right: 1.14rem;
padding-left: 1.14rem; padding-left: 1.14rem;
} }
#disconnection-btn:hover {
background-color: #b71c1c;
}
} }
} }

View File

@@ -1,3 +1,4 @@
import { AuthService } from './../core/services/auth.service';
import { NotificationsComponent } from './../core/notifications/notifications.component'; import { NotificationsComponent } from './../core/notifications/notifications.component';
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { LoginComponent } from '../login/login.component'; import { LoginComponent } from '../login/login.component';
@@ -7,15 +8,14 @@ import { LoginComponent } from '../login/login.component';
templateUrl: './header.component.html', templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'] styleUrls: ['./header.component.scss']
}) })
export class HeaderComponent implements OnInit { export class HeaderComponent {
@ViewChild('loginForm', {static: true}) loginForm: LoginComponent; @ViewChild('loginForm', {static: true}) loginForm: LoginComponent;
constructor() { } constructor(
private authService: AuthService
) {}
ngOnInit() { isAuthenticated(): boolean {
} return this.authService.isAuthenticated();
helloWorld() {
NotificationsComponent.info('Hello world!');
} }
} }

View File

@@ -1,3 +1,4 @@
import { AuthService } from './../core/services/auth.service';
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { User } from './../core/entities'; import { User } from './../core/entities';
import { ModalDirective } from 'angular-bootstrap-md'; import { ModalDirective } from 'angular-bootstrap-md';
@@ -9,21 +10,19 @@ import { NotificationsComponent } from '../core/notifications/notifications.comp
templateUrl: './login.component.html', templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'] styleUrls: ['./login.component.scss']
}) })
export class LoginComponent implements OnInit { export class LoginComponent {
model: User = User.new(); model: User = User.new();
@ViewChild('loginModal', {static: true}) loginModal: ModalDirective; @ViewChild('loginModal', {static: true}) loginModal: ModalDirective;
constructor( constructor(
private userService: UserService private userService: UserService,
private authService: AuthService
) {} ) {}
ngOnInit() {
}
onSubmit(): void { onSubmit(): void {
this.userService.login(this.model).subscribe(() => { this.userService.login(this.model).subscribe(user => {
NotificationsComponent.success('Connexion réussie.'); NotificationsComponent.success('Connexion réussie.');
this.authService.setAuthenticated(user);
this.loginModal.hide(); this.loginModal.hide();
}, ex => { }, ex => {
console.error('Error during login attempt: ', ex); console.error('Error during login attempt: ', ex);