From 5153b88df45cf2c45fe1c0ac2587f54c37828902 Mon Sep 17 00:00:00 2001 From: AntoineBonnafous-ParZivaL <74818304+AntoineBonnafous-ParZivaL@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:29:41 +0100 Subject: [PATCH 1/4] Ajout de l'authentification jwt + protection API server --- .../src/app/services/auth/auth-jwt.interceptor.ts | 11 ++++++++++- .../src/app/services/auth/auth-jwt.service.ts | 7 +++++++ .../bookstore/config/SecurityConfiguration.java | 9 +++++---- .../worldline/bookstore/web/rest/NewsResource.java | 14 ++++++-------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.interceptor.ts b/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.interceptor.ts index fdc4d6da..c5f68377 100644 --- a/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.interceptor.ts +++ b/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.interceptor.ts @@ -24,11 +24,20 @@ export class JwtInterceptor implements HttpInterceptor { req: HttpRequest, next: HttpHandler ): Observable> { + + let token = this.ng2localStorage.retrieve('authenticationToken') || this.ng2sessionStorage.retrieve('authenticationToken'); // On récupère le token sur le local storage du client ou bien sur la session deja existante // retrieve jwt token from client storage (local or session) with the key 'authenticationToken' // let token = this.ng2localStorage.retrieve(....) || this.ng2sessionStorage.retrieve(....); // verify token is present - // if (...){ + // if (...){ // set authorization header in the request with the token : 'Authorization: Bearer __token__' + if (token){ /*On créer cette entête de requete si le token existe ( c'est à dire si c'est un utilisateur qui est sur la page et s'est login au site)*/ + req = req.clone({ + setHeaders: { /*Création du pattern de l'entête de la requete*/ + Authorization: 'Bearer '+token /*Création de la requete avec de "type" bearer + token de l'utilisateur*/ + } + }); + } // req = req.clone({ // setHeaders: { // Authorization: .... diff --git a/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.service.ts b/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.service.ts index f192227d..4ad8c8dc 100644 --- a/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.service.ts +++ b/pw/pw-jwt-oauth/client/src/app/services/auth/auth-jwt.service.ts @@ -43,9 +43,16 @@ export class AuthServerProvider { // store the jwt in the credentials ( use storeAuthenticationToken ) // this.storeAuthenticationToken(.....); // return the jwt + let bearerToken = resp.headers.get('Authorization'); // On récupère notre Bearer token de l'entête de requete crée dans auth-jwt.interceptor.ts + if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') { /*Si le bearerToken existe et qu'on a bien le format bearer + token alors on peut continuer*/ + let jwt = bearerToken.slice(7, bearerToken.length); /*on récupère ainsi le token jwt de l'utilisateur via slice() */ + this.storeAuthenticationToken(jwt, rememberMe); /*On garde le token en place avec un système de rememberMe*/ + return jwt; /*On retourne le token jwt de l'utilisateur pour prouver son authenticité*/ + } return resp; } + loginWithToken(jwt: string, rememberMe: boolean) { if (jwt) { this.storeAuthenticationToken(jwt, rememberMe); diff --git a/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/config/SecurityConfiguration.java b/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/config/SecurityConfiguration.java index 4ce8239d..e6b28b38 100644 --- a/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/config/SecurityConfiguration.java +++ b/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/config/SecurityConfiguration.java @@ -90,18 +90,19 @@ protected void configure(HttpSecurity http) throws Exception { .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() - .antMatchers("/api/register").permitAll() + .antMatchers("/api/news/like/**").authenticated() //Permet de dire que pour acceder à /api/news/like/** il faut d'abord s'authentifier au site, donc une personne sans compte ou pas connectée ne pourra pas liker un post. + .antMatchers("/api/register").permitAll() .antMatchers("/api/activate").permitAll() .antMatchers("/api/authenticate").permitAll() .antMatchers("/api/account/reset_password/init").permitAll() .antMatchers("/api/account/reset_password/finish").permitAll() .antMatchers("/api/profile-info").permitAll() - .antMatchers("/api/**").permitAll() // authenticated() <== for tests!! //TODO remove it + //.antMatchers("/api/**").permitAll() // authenticated() <== for tests!! //TODO remove it .antMatchers("/management/health").permitAll() .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) .antMatchers("/v2/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN) - // .and() - // .apply(securityConfigurerAdapter()) + .and() + .apply(securityConfigurerAdapter()) ; // TODO uncomment this line to activate JWT filter diff --git a/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/web/rest/NewsResource.java b/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/web/rest/NewsResource.java index 9a23014c..c7e48e6a 100644 --- a/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/web/rest/NewsResource.java +++ b/pw/pw-jwt-oauth/server/src/main/java/com/worldline/bookstore/web/rest/NewsResource.java @@ -1,7 +1,7 @@ package com.worldline.bookstore.web.rest; import com.worldline.bookstore.domain.News; - +import com.worldline.bookstore.security.AuthoritiesConstants; import com.worldline.bookstore.repository.NewsRepository; import com.worldline.bookstore.web.rest.util.HeaderUtil; import io.github.jhipster.web.util.ResponseUtil; @@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; - +import org.springframework.security.access.annotation.Secured; /* On importe ce package afin de pouvoir sécuriser des méthodes ou des classes */ import javax.validation.Valid; import java.net.URI; import java.net.URISyntaxException; @@ -42,7 +42,7 @@ public NewsResource(NewsRepository newsRepository) { * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/news") - + @Secured({ AuthoritiesConstants.USER}) /*On protège la méthode createNews avec @Secured(), tout les personnes ayant le rôle USER peuvent créer une news */ public ResponseEntity createNews(@Valid @RequestBody News news) throws URISyntaxException { log.debug("REST request to save News : {}", news); if (news.getId() != null) { @@ -68,7 +68,7 @@ public ResponseEntity createNews(@Valid @RequestBody News news) throws URI * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/news") - + @Secured({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN })/*On protège la méthode update avec @Secured(), tout les personnes ayant le rôle USER et ADMIN peuvent l'utiliser*/ public ResponseEntity updateNews(@Valid @RequestBody News news) throws URISyntaxException { log.debug("REST request to update News : {}", news); if (news.getId() == null) { @@ -86,7 +86,7 @@ public ResponseEntity updateNews(@Valid @RequestBody News news) throws URI * @return the ResponseEntity with status 200 (OK) and the list of news in body */ @GetMapping("/news") - + /*Tout le monde peut voir les news */ public List getAllNews() { log.debug("REST request to get all News"); List news = newsRepository.findAll(); @@ -101,7 +101,6 @@ public List getAllNews() { * with status 404 (Not Found) */ @GetMapping("/news/{id}") - public ResponseEntity getNews(@PathVariable Long id) { log.debug("REST request to get News : {}", id); var optNews = newsRepository.findById(id); @@ -115,7 +114,7 @@ public ResponseEntity getNews(@PathVariable Long id) { * @return the ResponseEntity with status 200 (OK) */ @DeleteMapping("/news/{id}") - + @Secured({AuthoritiesConstants.ADMIN}) /*Seuls les admins peuvent supprimer une news */ public ResponseEntity deleteNews(@PathVariable Long id) { log.debug("REST request to delete News : {}", id); newsRepository.deleteById(id); @@ -131,7 +130,6 @@ public ResponseEntity deleteNews(@PathVariable Long id) { * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/news/like/{id}") - public ResponseEntity addLikeforNews(@PathVariable Long id) throws URISyntaxException { log.debug("REST request to add like to News : {}", id); var optNews = newsRepository.findById(id); From bd31d4d3b09195642d7e009052d446eedcc529ef Mon Sep 17 00:00:00 2001 From: Maximalic <60603482+Maximalic@users.noreply.github.com> Date: Mon, 13 Feb 2023 15:48:20 +0100 Subject: [PATCH 2/4] Changement Client-Side --- pw/pw-jwt-oauth/client/src/app/home/home.html | 15 +++++++++------ pw/pw-jwt-oauth/client/src/app/home/home.ts | 4 ++-- .../app/services/auth/principal.service.ts | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/pw/pw-jwt-oauth/client/src/app/home/home.html b/pw/pw-jwt-oauth/client/src/app/home/home.html index 08d6cdbe..ca4d3e92 100644 --- a/pw/pw-jwt-oauth/client/src/app/home/home.html +++ b/pw/pw-jwt-oauth/client/src/app/home/home.html @@ -25,13 +25,16 @@

{{message}}

{{currentNew.author}} {{currentNew.category}} {{currentNew.content}} - - + + + - - - - + + + + + + diff --git a/pw/pw-jwt-oauth/client/src/app/home/home.ts b/pw/pw-jwt-oauth/client/src/app/home/home.ts index 48840ea2..52119ed3 100644 --- a/pw/pw-jwt-oauth/client/src/app/home/home.ts +++ b/pw/pw-jwt-oauth/client/src/app/home/home.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; - +import {Principal} from '../services/auth/principal.service'; //On fait le lien à principal.service pour avoir les fonctions isAdmin, IsUser... import { NewsService } from '../services/newsService'; import { News } from '../beans/news'; @@ -15,7 +15,7 @@ export class Home implements OnInit { newsOfTheDay: News = {}; nextNews: News = {}; - constructor(private newsService: NewsService) {} + constructor(private newsService: NewsService, public principal: Principal) {} //On veut pouvoir savoir les permissions de l'utilisateur ngOnInit() { this.updateNews(); diff --git a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts index a9b48ff5..0ba56154 100644 --- a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts +++ b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts @@ -54,6 +54,25 @@ export class Principal { return this.authenticated; } + //Si l'utilisateur est connecté et qu'il appartient aux admins, return true + isAdmin(): boolean { + return true; + if (this._identity && this._identity.authorities.indexOf("ROLE_ADMIN") !== -1) { + } else { + return false; //Sinon return false + } + } + + //Si l'utilsateur est connecté et qu'il fait parti des utilisateurs et qu'il n'est PAS admin, return true sinon return false + isUser(): boolean { + if (this.isIdentityResolved() && this._identity.authorities.indexOf("ROLE_USER") !== -1 && !this.isAdmin) { // + + return true; + } else { + return false; + } + } + isIdentityResolved(): boolean { return this._identity !== undefined; } From 9ab13a1e8cd0d54d7e2e447f3fc2bc40ebf91d9a Mon Sep 17 00:00:00 2001 From: Maximalic Date: Mon, 13 Feb 2023 15:53:58 +0100 Subject: [PATCH 3/4] Patch fonction IsAdmin() --- .../client/src/app/services/auth/principal.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts index 0ba56154..2a984140 100644 --- a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts +++ b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts @@ -56,8 +56,9 @@ export class Principal { //Si l'utilisateur est connecté et qu'il appartient aux admins, return true isAdmin(): boolean { - return true; + if (this._identity && this._identity.authorities.indexOf("ROLE_ADMIN") !== -1) { + return true; } else { return false; //Sinon return false } @@ -66,7 +67,6 @@ export class Principal { //Si l'utilsateur est connecté et qu'il fait parti des utilisateurs et qu'il n'est PAS admin, return true sinon return false isUser(): boolean { if (this.isIdentityResolved() && this._identity.authorities.indexOf("ROLE_USER") !== -1 && !this.isAdmin) { // - return true; } else { return false; From 3fceda37d212ac00817bb61c949b48c0eef691e5 Mon Sep 17 00:00:00 2001 From: AntoineBonnafous-ParZivaL <74818304+AntoineBonnafous-ParZivaL@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:28:10 +0100 Subject: [PATCH 4/4] Patch Client sided (fonction isUser() ) --- pw/pw-jwt-oauth/client/src/app/home/home.html | 10 ++++----- .../app/services/auth/principal.service.ts | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pw/pw-jwt-oauth/client/src/app/home/home.html b/pw/pw-jwt-oauth/client/src/app/home/home.html index ca4d3e92..3fbf75a9 100644 --- a/pw/pw-jwt-oauth/client/src/app/home/home.html +++ b/pw/pw-jwt-oauth/client/src/app/home/home.html @@ -29,12 +29,10 @@

{{message}}

- - - - - - + + + + diff --git a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts index 2a984140..98023d68 100644 --- a/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts +++ b/pw/pw-jwt-oauth/client/src/app/services/auth/principal.service.ts @@ -54,6 +54,19 @@ export class Principal { return this.authenticated; } + //Si l'utilsateur est connecté et qu'il fait parti des utilisateurs et qu'il n'est PAS admin, return true sinon return false + isUser(): boolean { + + if (this._identity && ( this._identity.authorities.indexOf("ROLE_USER")!==-1 || this._identity.authorities.indexOf("ROLE_ADMIN")!== -1 )) + { + return true; + } + else + { + return false; //Sinon return false + } + } + //Si l'utilisateur est connecté et qu'il appartient aux admins, return true isAdmin(): boolean { @@ -64,15 +77,6 @@ export class Principal { } } - //Si l'utilsateur est connecté et qu'il fait parti des utilisateurs et qu'il n'est PAS admin, return true sinon return false - isUser(): boolean { - if (this.isIdentityResolved() && this._identity.authorities.indexOf("ROLE_USER") !== -1 && !this.isAdmin) { // - return true; - } else { - return false; - } - } - isIdentityResolved(): boolean { return this._identity !== undefined; }