spring security et spring boot - lis-lab.fr · spring-boot-rest-security dans name, com.example...
TRANSCRIPT
Spring Security et Spring Boot
Achref El Mouelhi
Docteur de l’universite d’Aix-MarseilleChercheur en programmation par contrainte (IA)
Ingenieur en genie logiciel
H & H: Research and Training 1 / 26
Spring Boot Rest & Spring Security
Objectif
Securiser l’acces a nos ressources REST
Ce qu’il faut
Spring Security
H & H: Research and Training 2 / 26
Spring Boot Rest & Spring Security
Objectif
Securiser l’acces a nos ressources REST
Ce qu’il faut
Spring Security
H & H: Research and Training 2 / 26
Spring Boot Rest & Spring SecurityCreation de projet Spring Boot
Aller dans File > New > Other
Chercher Spring, dans Spring Boot selectionner Spring Starter Project et cli-quer sur Next >
Saisir
spring-boot-rest-security dans Name,
com.example dans Group,
springbootrestsecurity dans Artifact
com.example.demo dans Package
Cliquer sur Next
Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver,Spring Web, Spring Boot DevTools, Lombok et Spring Security
Cliquer sur Next puis sur Finish
H & H: Research and Training 3 / 26
Spring Boot Rest & Spring SecurityExplication
Le package contenant le point d’entree de notre application (la classecontenant le puclic static void main) est com.example.demo
Tous les autres packages dao, model... doivent etre dans le packagedemo.
Pour la suite, nous considerons
une entite Personne a definir dans com.example.demo.model
une interface DAO PersonneRepository a definir danscom.example.demo.dao
un controleur REST PersonneController a definir danscom.example.demo.dao
H & H: Research and Training 4 / 26
Spring Boot Rest & Spring SecurityExplication
Le package contenant le point d’entree de notre application (la classecontenant le puclic static void main) est com.example.demo
Tous les autres packages dao, model... doivent etre dans le packagedemo.
Pour la suite, nous considerons
une entite Personne a definir dans com.example.demo.model
une interface DAO PersonneRepository a definir danscom.example.demo.dao
un controleur REST PersonneController a definir danscom.example.demo.dao
H & H: Research and Training 4 / 26
Creons une entite Personne dans com.example.demo.model
package com.example.demo.model;
import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
@NoArgsConstructor@AllArgsConstructor@Data@Entitypublic class Personne {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long num;private String nom;private String prenom;
}
H & H: Research and Training 5 / 26
Spring Boot & REST
Preparons notre interface DAO PersonneRepository
package com.example.demo.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.Personne;
public interface PersonneRepository extendsJpaRepository<Personne, Long> {
}
H & H: Research and Training 6 / 26
Spring Boot Rest & Spring SecurityCreons le controleur REST suivant
@CrossOrigin@RestControllerpublic class PersonneRestController {
@Autowiredprivate PersonneRepository personneRepository;
@GetMapping("/personnes")public List<Personne> getPersonnes() {
return personneRepository.findAll();}
@GetMapping("/personnes/{id}")public Personne getPersonne(@PathVariable("id") long id) {
return personneRepository.findById(id).orElse(null);}
@PostMapping("/personnes")public Personne addPersonne(@RequestBody Personne personne) {
return personneRepository.save(personne);}
}
H & H: Research and Training 7 / 26
Spring Boot Rest & Spring Security
Dans application.properties, ajoutons les donnees permettant laconnexion a la base de donnees et la configuration de Hibernate
spring.datasource.url = jdbc:mysql://localhost:3306/boot?useSSL=false&serverTimezone=UTC
spring.datasource.username = rootspring.datasource.password = rootspring.jpa.hibernate.ddl-auto = updatespring.jpa.show-sql = truespring.jpa.properties.hibernate.dialect = org.hibernate.dialect
.MySQL5Dialectspring.jpa.hibernate.naming.physical-strategy = org.hibernate.
boot.model.naming.PhysicalNamingStrategyStandardImpl
L’ajout de la propriete spring.jpa.hibernate.naming.physical-strategy
permet de forcer Hibernate a utiliser les memes noms pour les tables et les colonnesque les entites et les attributs.
H & H: Research and Training 8 / 26
Spring Boot Rest & Spring Security
Pour tester
Il faut aller sur http://localhost:8080/personnes ou surhttp://localhost:8080/personnes/1.
Constat
Toutes nos ressources sont exposees : pour recuperer les donnees, ilsuffit de connaıtre l’URL.
Question
Comment faire pour securiser l’acces a nos ressources REST ?
H & H: Research and Training 9 / 26
Spring Boot Rest & Spring Security
Pour tester
Il faut aller sur http://localhost:8080/personnes ou surhttp://localhost:8080/personnes/1.
Constat
Toutes nos ressources sont exposees : pour recuperer les donnees, ilsuffit de connaıtre l’URL.
Question
Comment faire pour securiser l’acces a nos ressources REST ?
H & H: Research and Training 9 / 26
Spring Boot Rest & Spring Security
Pour tester
Il faut aller sur http://localhost:8080/personnes ou surhttp://localhost:8080/personnes/1.
Constat
Toutes nos ressources sont exposees : pour recuperer les donnees, ilsuffit de connaıtre l’URL.
Question
Comment faire pour securiser l’acces a nos ressources REST?
H & H: Research and Training 9 / 26
Spring Boot Rest & Spring SecuritySolution
utiliser Spring Security
Etapes
Creer une classe SecurityConfig pour la configuration de lasecurite dans un packagecom.example.demo.configuration
Creer ou copier les entites, User et Role et les deux classes,UserDetailsImpl et UserDetailsServiceImpl, du projetassocie au chapitre Spring Security dans lecom.example.demo.security de ce projet
H & H: Research and Training 10 / 26
Spring Boot Rest & Spring SecuritySolution
utiliser Spring Security
Etapes
Creer une classe SecurityConfig pour la configuration de lasecurite dans un packagecom.example.demo.configuration
Creer ou copier les entites, User et Role et les deux classes,UserDetailsImpl et UserDetailsServiceImpl, du projetassocie au chapitre Spring Security dans lecom.example.demo.security de ce projet
H & H: Research and Training 10 / 26
Spring Boot Rest & Spring SecurityDans com.example.demo.configuration, definissons la classe SecurityConfig
package com.example.demo.configuration;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.
builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.
HttpSecurity;import org.springframework.security.config.annotation.web.configuration
.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration
.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.UserDetailsService
;import org.springframework.security.crypto.password.NoOpPasswordEncoder
;@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {
H & H: Research and Training 11 / 26
Spring Boot Rest & Spring SecuritySuite de SecurityConfig
@Autowiredprivate UserDetailsService userDetailsService;@Beanpublic static NoOpPasswordEncoder passwordEncoder() {return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
@Autowiredpublic void configure(AuthenticationManagerBuilder auth) throws
Exception {auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());}
@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and()
.authorizeRequests().anyRequest().fullyAuthenticated();http.httpBasic();http.csrf().disable();
}
H & H: Research and Training 12 / 26
Spring Boot Rest & Spring Security
Contenu de l’entite Role
@NoArgsConstructor@AllArgsConstructor@Data@Entitypublic class Role {
@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Long id;String titre;
}
H & H: Research and Training 13 / 26
Spring Boot Rest & Spring SecurityContenu de l’entite User
@NoArgsConstructor@AllArgsConstructor@Data@Entitypublic class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Long num;String userName;String password;@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.
REMOVE }, fetch = FetchType.EAGER)List<Role> roles = new ArrayList<Role>();
}
fetch = FetchType.EAGER pour indiquer que la relation doit etre chargee enmeme temps que l’entite User.
H & H: Research and Training 14 / 26
Spring Boot Rest & Spring Security
Contenu de UserRepository
public interface UserRepository extendsJpaRepository<User, Long> {public User findByUserName(String username);
}
La methode findByUserName sera utilisee plus tard.
Contenu de
RoleRepository
public interface RoleRepository extendsJpaRepository<Role, Long> {
}
H & H: Research and Training 15 / 26
Spring Boot Rest & Spring Security
Contenu de UserRepository
public interface UserRepository extendsJpaRepository<User, Long> {public User findByUserName(String username);
}
La methode findByUserName sera utilisee plus tard. Contenu de
RoleRepository
public interface RoleRepository extendsJpaRepository<Role, Long> {
}
H & H: Research and Training 15 / 26
Spring Boot Rest & Spring Security
Creons une classe qui implemente l’interface UserDetailsService
package com.example.demo.security;
import org.springframework.stereotype.Service;
@Servicepublic class UserDetailsServiceImpl implements
UserDetailsService {}
Cette classe implemente l’interface UserDetailsService, elle doit doncimplementer la methode loadUserByUserName() qui retourne un objet dela claase qui implemente l’interface UserDetails.
On utilise l’annotation Service pour dire qu’il s’agit d’un Component qu’onpeut injecter avec l’annotation Autowired et qui fait parti de la couchemetier.
H & H: Research and Training 16 / 26
Spring Boot Rest & Spring SecurityContenu de la classe qui implemente UserDetailsService
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.userdetails.UserDetailsService
;import org.springframework.security.core.userdetails.
UsernameNotFoundException;import org.springframework.stereotype.Service;import com.example.demo.dao.UserRepository;import com.example.demo.model.User;@Servicepublic class UserDetailsServiceImpl implements UserDetailsService {@Autowired UserRepository userRepository;@Overridepublic UserDetailsImpl loadUserByUsername(String username) throws
UsernameNotFoundException {User user = userRepository.findByUserName(username);if (null == user){
throw new UsernameNotFoundException("No user named " + username);} else {
return new UserDetailsImpl(user);}
}}
H & H: Research and Training 17 / 26
Spring Boot Rest & Spring Security
Creons une classe qui implemente l’interface UserDetails
package com.example.demo.security;
public class UserDetailsImpl implements UserDetails{
}
Cette classe implemente l’interface UserDetails, elle doit doncimplementer toutes les methodes que nous detaillerons dans la slidesuivante
H & H: Research and Training 18 / 26
Spring Boot Rest & Spring SecurityCreer une classe qui implemente l’interface UserDetails
import java.util.ArrayList;import java.util.Collection;import java.util.List;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.
SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import com.example.demo.model.Role;import com.example.demo.model.User;public class UserDetailsImpl implements UserDetails{private User user;public UserDetailsImpl(User user){
this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (final Role role: user.getRoles())authorities.add(new SimpleGrantedAuthority(role.getTitre()));
return authorities;}
H & H: Research and Training 19 / 26
@Overridepublic boolean isAccountNonExpired() {
return true;}@Overridepublic boolean isAccountNonLocked() {
return true;}@Overridepublic boolean isCredentialsNonExpired() {
return true;}@Overridepublic boolean isEnabled() {
return true;}@Overridepublic String getUsername() {
return user.getUserName();}@Overridepublic String getPassword() {
return user.getPassword();}
}
H & H: Research and Training 20 / 26
Spring Boot Rest & Spring Security
Avant de tester, lancez le projet pour que Spring cree les tablesensuite creez trois utilisateurs avec des roles differents
insert into role values (1, "ROLE_ADMIN"),(2, "ROLE_USER");
insert into user values (1, "wick", "wick"),(2, "john", "john"),(3, "alan", "alan");
insert into user_roles values (1, 1),(2, 2),(1, 2),(3, 1);
H & H: Research and Training 21 / 26
Spring Boot Rest & Spring Security
Pour tester
Il faut aller sur http://localhost:8080/personnes, s’authentifieravec les identifiants d’un utilisateur de la table users
H & H: Research and Training 22 / 26
Spring Boot Rest & Spring Security
Pour ajouter une personne
utiliser Postman en precisant la methode et l’urlhttp://localhost:8080/personnes
dans Headers, preciser la cle Content-Type et la valeurapplication/json
dans Body, cocher raw et selectionnerJSON(application/json)
Exemple de valeurs a persister
{"nom": "dalton","prenom": "jack"
}
H & H: Research and Training 23 / 26
Spring Boot Rest & Spring Security
Exercice 1
Tester, avec Postman, les trois methodes HTTP put et delete quipermettront de modifier ou supprimer une personne.
H & H: Research and Training 24 / 26
Spring Boot Rest & Spring Security
Exercice 2
Creer une application Angular qui permet a un utilisateur, via des in-terfaces graphiques) la gestion de personnes (ajout, modification, sup-pression, consultation et recherche) en utilisant les web services definispar Spring.
H & H: Research and Training 25 / 26
Dans personne.service.ts, on ajoute l’utilisateur a l’entete de la requete HTTP
import { Injectable } from ’@angular/core’;import { HttpClient, HttpHeaders } from ’@angular/common/http’;import { Personne } from ’../interfaces/personne’;
@Injectable({ providedIn: ’root’ })export class PersonneService {url = ’http://localhost:8080/personnes’;headers: HttpHeaders;constructor(private http: HttpClient) {
const username = ’wick’;const password = ’wick’;const user = username + ’:’ + password;this.headers = new HttpHeaders().set(’Authorization’, ’Basic ’ +
btoa(user));}getAll() {
return this.http.get<Array<Personne>>(this.url, { headers: this.headers });
}add(personne: Personne) {
return this.http.post(this.url, personne, { headers: this.headers});
}}
H & H: Research and Training 26 / 26