IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

Probleme de crossorigine avec Spring Boot Sécurity


Sujet :

Spring Java

  1. #1
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut Probleme de crossorigine avec Spring Boot Sécurity
    Bonjour à tous,

    J'ai un soucis de @CrossOrigin avec Sprig Boot sécurity.
    Ce que j'ai dans mon code pour l'instant ne fonctionne pas, malgré mes recherche sur le sujet.

    Dans mon pom.xml:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    Ma class d'API REST:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class ApiTempController {
        @Autowired
        private ApiTempJoin apiTempJoins;
    //    @Autowired
    //    private ApiGetDay apiGetDay;
        @GetMapping("api/last24")
        @CrossOrigin("*")
        public Iterable<ApiTempJoin> dataLast24(){
            return apiTempJoins.findByIdInvOrderLast24Temp();
        }
     
        @GetMapping("api/{day}")
        @CrossOrigin("*")
        public Iterable<ApiTempJoin> data1day(@PathVariable String day){
            return apiTempJoins.findByDay(day);
        }
     
        @PostMapping(value = "/api/getDay", consumes = {"application/json"})
        @CrossOrigin("*")
        public ApiGetDay getDay(@RequestBody ApiGetDay apiGetDay){
        String  oneDay = apiGetDay.getGetDay();
        System.out.println(oneDay);
        data1day(oneDay);
        return apiGetDay;
    }
    }
    Ma class gèrant la sécurité:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package fr.synergy.projet_THP.controlers.security;
     
    import org.springframework.context.annotation.Bean;
    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.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
     
     
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        public void configure (HttpSecurity http) throws Exception{
     
            http.cors().and().authorizeHttpRequests((requests) -> requests
                            .antMatchers("/admin", "/admin/index").permitAll()
                            .anyRequest().authenticated()
                    );
            http.cors().and().formLogin((form) -> form
                            .loginPage("/login")
                            .permitAll()
                    )
                    .logout((logout) -> logout.permitAll());
        }
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails user =
                    User.withDefaultPasswordEncoder()
                            .username("user")
                            .password("pwd")
                            .roles("USER")
                            .build();
     
            return new InMemoryUserDetailsManager(user);
        }
    }
    Voila je pense que j'ai mis le principale, je fait encore des essaies, mais pour l'instant, rien ne fonctionne.
    Donc, si quelqu'un de vous a une solution?
    Merci d'avance

  2. #2
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    Bonjour,

    Il faudrait donner l'erreur, pour que l'on puisse t'aider.

    Pour ma part, j'ai du dernièrement me confronter à Spring Security, et j'ai du implémenter un scénario précis.

    https://www.developpez.net/forums/d2.../#post11875369

    Je l'ai fait par jeton JWT.

    Et il y a toujours le CORS qui emmerde son monde.
    On peut le configurer de la façon suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Bean
    	public CorsConfigurationSource corsConfigurationSource() {
    		CorsConfiguration configuration = new CorsConfiguration();
    		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    		configuration.applyPermitDefaultValues();
    		configuration.addAllowedOrigin(client);
    		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", configuration);
    *
    		return source;
    	}
    Ici, on passe clairement en paramètre le client autorisé (par exemple http://localhost:4200). Mais si on est multiclient, comme mon projet, on a vite des problèmes.

    On peut aussi admettre tous clients, soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    @Bean("corsConfigurationSource")
    	public CorsConfigurationSource getCorsConfigurationSource() {
    		CorsConfiguration configuration = new CorsConfiguration();
    		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    		configuration.applyPermitDefaultValues();
    		configuration.addAllowedOrigin("*");
    		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", configuration);
    		return source;
    	}
    Cordialement.

  3. #3
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Bonjour et merci PhilippeGibault,

    Je vais essayer de regarder avec ce que tu m'a donné, mais ça me parait un cheminement complexe.

    Par contre comment tu utilise:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Bean
    	public CorsConfigurationSource corsConfigurationSource() {
    		CorsConfiguration configuration = new CorsConfiguration();
    		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    		configuration.applyPermitDefaultValues();
    		configuration.addAllowedOrigin(client);
    		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", configuration);
    *
    		return source;
    Tu le mets juste dans la classe gérant la sécurité?
    Il doit y avoir un appel de cette fonction?


    Sinon désolé voici l'erreur:
    La première et sans importance, elle est du a l'utilisation de la bibliothèque Chart.js, mais cela fonctionne même avec l'erreur.

    Nom : Screenshot_14.png
Affichages : 806
Taille : 222,1 Ko

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    C'est effectivement le CORS.

    Et c'est effectivement un truc qui emmerde tous le monde.

    En gros, ce qu'il te dit, c'est que celui qui appelle ton service REST (en l'occurrence par exemple http://localhost:4200 si tu développes avec Angular) n'est pas au même endroit que ton serveur Java Spring (exemple http://localhost:8080).

    Le CORS te dit donc que comme ce n'est pas la même origine, il refuse de donner suite à la requête.

    Tu peux permettre toutes origines de la façon suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    configuration.addAllowedOrigin("*");
    Ou alors rester dans la logique du je n'ai qu'un seul client:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    configuration.addAllowedOrigin(client);
    Et passer en paramètre ton client comme http://localhost:4200 (Si angular).

  5. #5
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    Et le but de code est en fait dans la classe de configuration de Spring Boot.

  6. #6
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    Pour être exact, le @Bean définit un bean pour le contexte Spring. Et j'injecte ce bean dans le filtre Spring security:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    @Bean
    	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    			return http
    				.authenticationProvider(authenticationProvider())
    				.cors().configurationSource(corsConfigurationSource())
    				.and()
    				.authorizeHttpRequests()
    					.antMatchers("/login/log").permitAll()
    					.antMatchers("/login/logout").permitAll()
    				.and()
    				.authorizeHttpRequests().anyRequest().authenticated()
    				.and()
    				.csrf().disable()	
    				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    				.and()
    				.addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
    				.build();
    	}

  7. #7
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Bonjour et merci PhilippeGibault pour ce complément d'info,

    Que j'ai arrivé a résoudre ce problème de Cors, car je n'ai plus le message, par contre ça ne fonctionne pas encore.

    Voici comment j'ai modifier mon code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    package fr.synergy.projet_THP.controlers.security;
     
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.Customizer;
    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.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
     
    import java.util.Arrays;
     
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        public void configure (HttpSecurity http) throws Exception{
     
            http.cors(Customizer.withDefaults()).authorizeHttpRequests((requests) -> requests
                            .antMatchers("/admin", "/admin/index").permitAll()
                            .anyRequest().authenticated()
                    );
            http.cors(Customizer.withDefaults()).formLogin((form) -> form
     
                            .loginPage("/login")
                            .permitAll()
                    )
                    .logout((logout) -> logout.permitAll());
        }
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails user =
                    User.withDefaultPasswordEncoder()
                            .username("user")
                            .password("pwd")
                            .roles("USER")
                            .build();
     
            return new InMemoryUserDetailsManager(user);
        }
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.applyPermitDefaultValues();
            configuration.addAllowedOrigin("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
     
            return source;
        }
    }
    Et voici le message d'erreur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
    Nom : Screenshot_15.jpg
Affichages : 779
Taille : 67,6 Ko

    ça ne serait pas a cause de l'authentification qu'il faut gérer avec JWT, ou c'est un autre soucis ?

    Sinon, quand je click sur le lien de l'API dans la console je m'authentifie et j'arrive sur mon JSON, donc je ne dois pas en être si loin.

  8. #8
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    Je suis en train justement de refaire les clients sur mon projet.

    Je JWT vient après. Là, il s'agit juste de permettre (ou pas) à un client d'accéder (ou pas) sur le serveur.

    Le CORS est la première étape.

    Dans mon projet perso, je veux juste permettre un seul client.

    Donc ce code doit suffire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    package com.calculateur.warhammer.rest.configuration.general;
     
    import java.util.Arrays;
     
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
     
    /**
     * Configuration pour les service REST pour Spring Boot
     * @author phili
     *
     */
    @ComponentScan(basePackages = {"com.calculateur.warhammer.rest.controller"})
    public class AbstractRestConfiguration implements WebMvcConfigurer{
     
    	@Value("${clientWeb}")
    	private String clientWeb;
     
    	@Bean("securityFilterChain")
    	public SecurityFilterChain getFilterChain(HttpSecurity http) throws Exception {
    			return http
    				.cors().configurationSource(getCorsConfigurationSource())
    					.and()
    				.csrf().disable()	
    				.build();
    	}
     
    	@Bean("corsConfigurationSource")
    	public CorsConfigurationSource getCorsConfigurationSource() {
    		CorsConfiguration configuration = new CorsConfiguration();
    		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    		configuration.applyPermitDefaultValues();
    		configuration.addAllowedOrigin(clientWeb);
    		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", configuration);
    		return source;
    	}	
    }
    Dans le SecurityFilterChain, ce qui n'est pas le cas de mon projet perso, on ajoutera par la suite l'authentification, à savoir quels services demandent une authentification, et la façon de le gérer (par un JWT par exemple).

  9. #9
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    En remarque général, je te recommande de faire "Simple" (car effectivement, Spring Security n'est pas forcement simple) et surtout de décomposer les problème.

    Le CORS est un problème, l'authentification en est un autre.

    Sur le post précédent:
    https://www.developpez.net/forums/d2.../#post11875369

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
    package com.alten.assistantnc.configuration.rest;
    *
    import java.util.Arrays;
    *
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Import;
    import org.springframework.security.authentication.AuthenticationProvider;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    *
    import com.alten.assistantnc.configuration.service.ConfigurationAssistantNCConfigurationService;
    import com.alten.assistantnc.security.AuthenticationProviderImpl;
    import com.alten.assistantnc.security.JWTAuthorizationFilter;
    import com.alten.assistantnc.security.JWTManagement;
    import com.alten.assistantnc.security.JWTManagementImpl;
    import com.alten.assistantnc.security.SecurityConstant;
    *
    @ComponentScan("com.alten.assistantnc.rest")
    @Import(ConfigurationAssistantNCConfigurationService.class)
    @EnableGlobalMethodSecurity(
    		  prePostEnabled = true, 
    		  securedEnabled = true, 
    		  jsr250Enabled = true)
    public class ConfigurationAssistantNCRest implements WebMvcConfigurer{
    *
    	@Value("${client}")
    	private String client; //Ici, j'injecte le client pour dire qu'au niveau du CORS, je n'authorise pas n'importe quoi.
    *
    	@Autowired
    	private UserDetailsService userService;
    *
    	@Bean
    	public AuthenticationProvider authenticationProvider() {
    		return new AuthenticationProviderImpl(userService);//Je réimplémente l'AuthenticationProvider de Spring pour utiliser mon propre service qui tape soit dans ma propre BDD, soit éventuellement dans un LDAP
    	}
    *
    	@Bean
    	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {//Chaine pour décrire le merdier à Spring security
    			return http
    				.authenticationProvider(authenticationProvider()) //On injecte son propre Provider qui sera utilisé par Spring 
    				.cors().configurationSource(corsConfigurationSource()) //Configuration du CORS
    				.and()
    				.authorizeHttpRequests() //Ici on va expliquer à Spring que les service de login peuvent être appelé par tous le monde.
    					.antMatchers("/login/log").permitAll()
    					.antMatchers("/login/logout").permitAll() //En fait, cette ligne est inutile. Côté client, il suffit de nettoyer le JWT.
    				.and()
    				.authorizeHttpRequests().anyRequest().authenticated() //Pour le reste, il faut un jeton
    				.and()
    				.csrf().disable()	 //Un autre mécanisme de sécurité à désactiver.
    				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    				.and()
    				.addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class) //Ici, on écrit un filtre qui va traité avant appel de service tous les JWT
    				.build();
    	}
    *
    	@Bean
    	public CorsConfigurationSource corsConfigurationSource() { //La configuration du CORS
    		CorsConfiguration configuration = new CorsConfiguration();
    		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    		configuration.applyPermitDefaultValues();
    		configuration.addAllowedOrigin(client);
    		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", configuration);
    *
    		return source;
    	}	
    *
    	@Bean
    	public JWTManagement jwtManagement() { //Une classe pour gérer les JWT de l'application
    		return new JWTManagementImpl();
    	}
    }

  10. #10
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Merci pour tes infos, si je comprends bien, tu me dis qu'en adaptant le code si dessous, je devrais résoudre mon problème de connexion et je devrais accéder a ma requête, sans me soucier de l'authentification pour l'instant.
    Excuse moi si je suis un peu lourd mais mon niveau est loin d’être aussi bon que le tien.


    Citation Envoyé par PhilippeGibault Voir le message
    Donc ce code doit suffire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    package com.calculateur.warhammer.rest.configuration.general;
     
    import java.util.Arrays;
     
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
     
    /**
     * Configuration pour les service REST pour Spring Boot
     * @author phili
     *
     */
    @ComponentScan(basePackages = {"com.calculateur.warhammer.rest.controller"})
    public class AbstractRestConfiguration implements WebMvcConfigurer{
     
        @Value("${clientWeb}")
        private String clientWeb;
     
        @Bean("securityFilterChain")
        public SecurityFilterChain getFilterChain(HttpSecurity http) throws Exception {
                return http
                    .cors().configurationSource(getCorsConfigurationSource())
                        .and()
                    .csrf().disable()    
                    .build();
        }
     
        @Bean("corsConfigurationSource")
        public CorsConfigurationSource getCorsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.applyPermitDefaultValues();
            configuration.addAllowedOrigin(clientWeb);
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }    
    }

    une petite explication:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @ComponentScan(basePackages = {"com.calculateur.warhammer.rest.controller"})
    Ce code permet d'avoir un lien vers le package du @RestController de l'API?

  11. #11
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    C'est parce que je ne me base pas sur le Spring Starter, donc je signale où sont mes controller. Tu n'as normalement pas besoin de ces lignes.

  12. #12
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Oui en effet je n'en ai pas besoin,

    Les choses avancent tout doucement, mais avance.

    Mon front fonctionne avec le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    package fr.synergy.projet_THP.security;
     
     
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.Customizer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
     
    import java.util.Arrays;
     
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig {
        @Bean("securityFilterChain")
        public SecurityFilterChain getFilterChain(HttpSecurity http) throws Exception {
     
            http.cors(Customizer.withDefaults())
     
                    .csrf().disable()
    //                .authorizeHttpRequests((requests) -> {requests
    //                .antMatchers("/admin", "/admin/index").permitAll()
    //                .anyRequest().authenticated();})
    //                .formLogin((form) -> form
    //                .loginPage("/login")
    //                .permitAll())
    //                .logout((logout) -> logout.permitAll())
            ;
            return http.build();
     
        }
     
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails user =
                    User.withDefaultPasswordEncoder()
                            .username("user")
                            .password("pwd")
                            .roles("USER")
                            .build();
     
            return new InMemoryUserDetailsManager(user);
        }
        @Bean("corsConfigurationSource")
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.applyPermitDefaultValues();
            configuration.addAllowedOrigin("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
     
            return source;
        }
    }
    Mais par contre dés que je décommente le code de l'autentification:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    http.cors(Customizer.withDefaults())
    
            .csrf().disable()
            .authorizeHttpRequests((requests) -> {requests
            .antMatchers("/admin", "/admin/index").permitAll()
            .anyRequest().authenticated();})
            .formLogin((form) -> form
            .loginPage("/login")
            .permitAll())
            .logout((logout) -> logout.permitAll())
    ;
    return http.build();
    Je retrouve avec cet erreur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
    Nom : Screenshot_15.jpg
Affichages : 736
Taille : 67,6 Ko

    La suite est de gérer avec JWT ou il y a un autre moyen ?

  13. #13
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    Le mieux est vraiment de le faire par étape (car c'est juste chiant).

    Déjà, il y a, en plus du CORS le CSFR (pire que le CORS).
    https://fr.wikipedia.org/wiki/Cross-...equest_forgery

    On dit à Spring de ne pas prendre en compte par:
    Ensuite le CORS. Le mieux est de le spécifier par un bean dans le contexte Spring.
    Soit si on n'en veut pas (c'est à dire si on autorise toutes les origines):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Bean("corsConfigurationSource")
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.applyPermitDefaultValues();
            configuration.addAllowedOrigin("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
    *
            return source;
        }
    L'annotation @Bean sert à dire que l'on crée un bean dans le contexte Spring. Encore faut-il l'utiliser, dont l'injecter dans le merdier où il est sensé être utilisé.
    Soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    .cors().configurationSource(getCorsConfigurationSource())
    Et non:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    http.cors(Customizer.withDefaults())
    Ensuite, pour tester, tu permets à tout le monde (pour l'instant) d'accéder à l'application.
    Donc normalement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    .authorizeHttpRequests()
    Là, normalement, tu accède à tous tes services REST.

    La suite
    Après on regarde si on peut accéder aux services REST de login, mais pas le reste.
    Donc, en l'occurence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    .authorizeHttpRequests() 
    					.antMatchers("/login/log").permitAll()
    				.and()
    				.authorizeHttpRequests().anyRequest().authenticated()
    Ici, on explique que tous les services doivent s’authentifier, excepté celui de login ("/login/log"). Donc en résumé, tu dois pouvoir à ce stade accéder au service de login, mais pas au reste (sous entendu que l'on a rien implémenté dans le service de login, excepté le strict minimum.

    Etape plus lointaine
    A partir de là, on implémente le controller login et on se pose la question du jeton JWT. Car effectivement, vu que l'application est cliente et consommatrice de service Web, c'est le JWT qui donne l'information si le client est authentifié, et peut accéder ou pas au service.

  14. #14
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    A titre d'information, pour implémenter mon scénario, j'ai mis 2 semaines. Donc non, le sujet est difficile, et doit effectivement être fait et mis en place au début du projet.

  15. #15
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    J'essaie pourtant de suivre tes indications à la lettre, mais je n'arrive pas a injecter "getCorsConfigurationSource()":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    http.csrf().disable()
            .cors().configurationSource(getCorsConfigurationSource())
    Il n'est pas du tout reconnu, donc du coup je suis dans l'incapacité d'aller plus loin.

    Tout ce que j'arrive à faire sans avoir d'erreur, c'est ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    @Bean("securityFilterChain")
        public SecurityFilterChain getFilterChain(HttpSecurity http) throws Exception {
    
            http.csrf().disable()
                    .cors().configurationSource(corsConfigurationSource())
                    .and()
                    .authorizeHttpRequests().anyRequest().authenticated();
            return http.build();
    Mais évidement ça ne fonctionne pas

  16. #16
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    C'est le stade 1. Si tu mets un point d'arrêt sur un web service au hasard, tu dois pouvoir t'y arrêter. Est-ce le cas?

    Eclipse permet de le faire, et IntelliJ aussi, normalement.

  17. #17
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Merci, je pense avoir atteins le résultat que j’attends.

    Mes appels sur les services rest ne doivent pas avoir d'authentification car il sont accessible à tous, par contre je ne sais pas si c'est une bonne pratique?
    Je veux juste protéger mon back avec un login mot de passe et un rôle pour définir les action possible sur mon back.
    Le code ci dessous le fait à par les rôles qui ne sont pas codé, reste a voir si il est bien sécurisé.

    Voici mon code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    package fr.synergy.projet_THP.security;
     
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.Customizer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
     
    import java.util.Arrays;
     
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig {
        @Bean("securityFilterChain")
        public SecurityFilterChain getFilterChain(HttpSecurity http) throws Exception {
     
            http.csrf().disable()
                    .cors().configurationSource(corsConfigurationSource())
                    .and()
                    .authorizeHttpRequests()
                    .antMatchers("/api/**").permitAll()
                    .and()
                    .authorizeHttpRequests((requests) -> {requests
                    .antMatchers("/admin", "/admin/index").permitAll()
                    .anyRequest().authenticated();})
                    .formLogin((form) -> form
                    .loginPage("/login")
                    .permitAll())
                    .logout((logout) -> logout.permitAll())
            ;
            return http.build();
     
        }
     
     
     
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails user =
                    User.withDefaultPasswordEncoder()
                            .username("user")
                            .password("pwd")
                            .roles("USER")
                            .build();
     
            return new InMemoryUserDetailsManager(user);
        }
        @Bean("corsConfigurationSource")
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.applyPermitDefaultValues();
            configuration.addAllowedOrigin("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
     
            return source;
     
        }
     
    }
    Peux tu me dire si cela te semble correct en fonction de ma stratégie de sécurité?
    Une question sur les rôles, peut on donner acces a la visualisation d'une page du back sans donner les autorisations de réaliser des action sur cette page.
    C'est a dire donner un accès uniquement en visualisation?

  18. #18
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    permitAll() signifie justement que tous le monde peut acceder au service REST (ce qui implique que c'est sans mot de passe).

    .formLogin((form) -> form
    .loginPage("/login")
    Ces lignes de code indiquent que tu demande à Spring d'envoyer son propre formulaire de login.

  19. #19
    Membre habitué
    Homme Profil pro
    En reconversion
    Inscrit en
    Mai 2006
    Messages
    482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : En reconversion

    Informations forums :
    Inscription : Mai 2006
    Messages : 482
    Points : 161
    Points
    161
    Par défaut
    Citation Envoyé par PhilippeGibault Voir le message
    .formLogin((form) -> form
    .loginPage("/login")
    Ces lignes de code indiquent que tu demande à Spring d'envoyer son propre formulaire de login.
    Par contre même avec ce code ma page de login perso s'affiche en la mettant à la racine de templates et en respectant certains paramètre, elle vient du coup supplanter la page login par défaut de Spring Sécurity.

    Sinon mon code te parait il suffisamment sécurisé?

    Et au niveau des rôles à t'on avis on peut donner accès uniquement en visualisation les pages de mon back?

  20. #20
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    461
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 461
    Points : 894
    Points
    894
    Billets dans le blog
    5
    Par défaut
    A priori, oui, mais c'est le back qui semble tout faire.

    Tout faire, y compris l'IHM (avec thymeleaf?).

    Or, aujourd'hui, on ne veut surtout pas de ça. Le client est une application indépendante qui vit sa vie tout seul et qui consomme le back avec toute la logique métier souvent complexe.

    Et du coup, le back vit sa vie et envoie les informations demandées sans s'occuper de l'IHM. C'est un serveur, un service....

    L'IHM ne fait que afficher.

    C'est pour ça que l'on sépare l'IHM et le serveur. Les deux métiers dev Back et dev Front n'ont d'ailleurs plus rien à voir.

    Intérêt économique: on peut réécrire le client sans toucher le front ou inversement.

    C'est pour ça qu'en général, le formulaire de connexion est côté client. C'est du client (application indépendante) que l'on se connecte sur le serveur. Et on ne le fait qu'une fois.

    Par la suite, on traine le JWT qui possède toute la logique de connexion. Pour vérifier si le client peut se connecter à un service REST, il suffit de lire le JWT envoyé.

Discussions similaires

  1. Réponses: 7
    Dernier message: 02/12/2018, 10h28
  2. Réponses: 2
    Dernier message: 20/04/2011, 21h48
  3. Probleme de session avec spring MVC et tomcat
    Par jalalos dans le forum Spring Web
    Réponses: 0
    Dernier message: 13/08/2009, 11h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo