Bonjour, j'implémente Spring Security sur une application Springboot-angular. Dans mon UserController, j'ai mappé une méthode avec l'url suivante: /api/user/login pour connecter l'utilisateur et récupérer ses informations. Quand je démarre l'application angular, l'url suivante: http://localhost:8080/api/user/login est déclenchée avec un code d'erreur 405. Je suppose que cela est dû au fait que j'ai ajouté la fonctionnalité Spring security. J'ai plusieurs questions:

1) est-ce normal que l'url : http://localhost:8080/api/user/login, soit déclenchée au démarage de l'application angular ?. Je ne vois pas pourquoi, car dans mon application, je veux que la connection d'un utilisateur soit uniquement géré par un formulaire dans une pop up dédié.

2) Si c'est normal, quelle est le but de cette requête ? Et comment dois implémenter la méthode du controlleur dédié à cette url ?

3) dans mon application angular, j'ai configuré proxy.config.json comme suit
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
    {
      "/api/*": {
 
        "target":  {
           "host": "localhost",
           "protocol": "http:",
           "port": 8080
         },
        "secure": false,
         "changeOrigin": true,
         "logLevel": "info"
      }
    }
pour rediriger chaque requête http://localhost:42OO/api vers http://localhost:8080/api. Pour que ça soit pris en compte, je lance la partie angular avec cette commande: "ng serve --proxy-config proxy.config.json".

Quand "http://localhost:8080/api/user/login" est déclenché, j'ai le message d'erreur suivant:

Blocage d’une requête multiorigines (Cross-Origin Request) : la politique « Same Origin » ne permet pas de consulter la ressource distante située sur http://localhost:8080/login. Raison : l’en-tête CORS « Access-Control-Allow-Origin » est manquant.

Donc, comment gérer ceci ?

Voici la configuration back pour 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
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
 
Fichier WebSecurityConfig.java
 
    package com.example.demoImmobilierBack;
 
    import javax.sql.DataSource;
 
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    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.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
    import com.example.demoImmobilierBack.service.MyUserDetailsService;
 
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
        @Bean
        public UserDetailsService userDetailsService() {
            return new MyUserDetailsService();
        }
 
        @Autowired
        private DataSource dataSource;
 
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
 
        @Bean
        public DaoAuthenticationProvider authenticationProvider() {
            DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
            authProvider.setUserDetailsService(userDetailsService());
            authProvider.setPasswordEncoder(passwordEncoder());
            return authProvider;
        }
 
        @Bean("authenticationManager")
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
    }
 
        @Override
        protected void configure(AuthenticationManagerBuilder auth) {
            auth.authenticationProvider(authenticationProvider());
        }
 
        @Override
        protected void configure(HttpSecurity http) throws Exception {
        	http         
            .headers()
             .frameOptions().sameOrigin()
             .and()
               .authorizeRequests()
                .antMatchers("/**/*.scss", "/**/*.js","/**/*.html").permitAll()
                   .antMatchers("/").permitAll()
                   .antMatchers("/admin/**").hasRole("ADMIN")
                   .anyRequest().authenticated()
                   .and()
               .formLogin()
                   .loginPage("/api/user/login")
                   .defaultSuccessUrl("/")
    //               .failureUrl("/login?error")
                   .failureUrl("/")
                   .permitAll()
                   .and()
               .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/")
    //            .logoutSuccessUrl("/login?logout")
                .deleteCookies("my-remember-me-cookie")
                   .permitAll()
                   .and()
                .rememberMe()
                 //.key("my-secure-key")
                 .rememberMeCookieName("my-remember-me-cookie")
                 .tokenRepository(persistentTokenRepository())
                 .tokenValiditySeconds(24 * 60 * 60)
                 .and()
               .exceptionHandling()
               .and()
               .csrf().disable();
        }
 
        PersistentTokenRepository persistentTokenRepository(){
            JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
            tokenRepositoryImpl.setDataSource(dataSource);
            return tokenRepositoryImpl;
        }
 
    }
Le controlleur utilisateur UserController.java
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
 
    package com.example.demoImmobilierBack.controller;
 
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
 
    import com.example.demoImmobilierBack.dto.UserDTO;
    import com.example.demoImmobilierBack.service.UserService;
 
    @RestController
    @RequestMapping({"/api/user"})
    public class UserController {
 
        @Autowired
        private UserService userService;
 
        @RequestMapping(value = "/login",
        method = RequestMethod.POST)
        public @ResponseBody UserDTO login(@RequestBody UserDTO userDTO){
        	String message = userService.checkIfUserExistsAndGoodCredential(userDTO);
        	if (message.isEmpty()) {
        		userDTO = userService.findByEmailAndPassword(userDTO.getEmail(), userDTO.getPassword());
        		userDTO.setPassword("");
        	} else {
        		userDTO.setMessage(message);
        	}
            return userDTO;
        }
Le fichier InitialDataLoader.java
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 
    package com.example.demoImmobilierBack.service;
 
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;
 
    import javax.transaction.Transactional;
 
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Component;
 
    import com.example.demoImmobilierBack.model.Privilege;
    import com.example.demoImmobilierBack.model.Role;
    import com.example.demoImmobilierBack.model.User;
    import com.example.demoImmobilierBack.repository.PrivilegeRepository;
    import com.example.demoImmobilierBack.repository.RoleRepository;
    import com.example.demoImmobilierBack.repository.UserRepository;
 
    @Component
    public class InitialDataLoader implements
      ApplicationListener<ContextRefreshedEvent> {
 
        boolean alreadySetup = false;
 
        @Autowired
        private UserRepository userRepository;
 
        @Autowired
        private RoleRepository roleRepository;
 
        @Autowired
        private PrivilegeRepository privilegeRepository;
 
        @Autowired
        private PasswordEncoder passwordEncoder;
 
        @Override
        @Transactional
        public void onApplicationEvent(ContextRefreshedEvent event) {
 
            if (alreadySetup)
                return;
            Privilege readPrivilege
              = createPrivilegeIfNotFound("READ_PRIVILEGE");
            Privilege writePrivilege
              = createPrivilegeIfNotFound("WRITE_PRIVILEGE");
 
            List<Privilege> adminPrivileges = Arrays.asList(
              readPrivilege, writePrivilege);        
            createRoleIfNotFound("ADMIN", adminPrivileges);
            createRoleIfNotFound("LOUEUR", adminPrivileges);
            createRoleIfNotFound("ACHETER", adminPrivileges);
            createRoleIfNotFound("DEPOSE_LOUER", adminPrivileges);
            createRoleIfNotFound("DEPOSE_ACHETER", adminPrivileges);
            createRoleIfNotFound("AGENCE", adminPrivileges);
            createRoleIfNotFound("PROMOTEUR", adminPrivileges);
 
 
 
            Role adminRole = roleRepository.findByName("ADMIN");
 
            User user = userRepository.findByEmail("flamant@club-internet.fr");
            if (user == null) {
    	        user = new User();
    	        user.setGender("M");
    	        user.setFirstName("adminFirstName");
    	        user.setLastName("adminLastName");
    	        user.setRaisonSociale("adminLastName");
    	        user.setName("PARTICULIER");
    	        user.setLastName("adminLastName");
    	        user.setPassword(passwordEncoder.encode("adminPassword"));
    	        user.setEmail("flamant@club-internet.fr");
    	        user.setRoles(Arrays.asList(adminRole));
    	        user.setEnabled(true);
    	        user.setAccountNonExpired(true);
    	        user.setAccountNonLocked(true);
    	        user.setCredentialsNonExpired(true);
    	        userRepository.save(user);
            }
 
            alreadySetup = true;
        }
 
        @Transactional
        private Privilege createPrivilegeIfNotFound(String name) {
 
            Privilege privilege = privilegeRepository.findByName(name);
            if (privilege == null) {
                privilege = new Privilege(name);
                privilegeRepository.save(privilege);
            }
            return privilege;
        }
 
        @Transactional
        private Role createRoleIfNotFound(
          String name, Collection<Privilege> privileges) {
 
            Role role = roleRepository.findByName(name);
            if (role == null) {
                role = new Role(name);
                role.setPrivileges(privileges);
                roleRepository.save(role);
            }
            return role;
        }
    }
L'impémentation UserDetailsService:
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
85
86
87
88
89
90
91
92
93
94
 
    package com.example.demoImmobilierBack.service;
 
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;
 
    import javax.transaction.Transactional;
 
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.MessageSource;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
 
    import com.example.demoImmobilierBack.model.Privilege;
    import com.example.demoImmobilierBack.model.Role;
    import com.example.demoImmobilierBack.model.User;
    import com.example.demoImmobilierBack.repository.RoleRepository;
    import com.example.demoImmobilierBack.repository.UserRepository;
 
    @Service("userDetailsService")
    @Transactional
    public class MyUserDetailsService implements UserDetailsService {
 
        @Autowired
        private UserRepository userRepository;
 
        //@Autowired
        //private IUserService service;
 
        @Autowired
        private MessageSource messages;
 
        @Autowired
        private RoleRepository roleRepository;
 
        @Override
        public UserDetails loadUserByUsername(String email)
          throws UsernameNotFoundException {
 
            User user = userRepository.findByEmail(email);
            if (user == null) {
                return new org.springframework.security.core.userdetails.User(
                  " ", " ", true, true, true, true, 
                  (Collection<? extends GrantedAuthority>) getAuthorities(Arrays.asList(roleRepository.findByName("ROLE_USER"))));
            }
 
            return new org.springframework.security.core.userdetails.User(
              user.getEmail(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), 
              user.isAccountNonLocked(), getRolesAuthorities(user.getRoles()));
        }
 
        private Collection<? extends GrantedAuthority> getRolesAuthorities(
        	      Collection<Role> roles) {
    		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    		for (Role role :roles) {
    			authorities.add(new SimpleGrantedAuthority(role.getName()));
    		}
 
    		return authorities;
        }
 
        private Collection<? extends GrantedAuthority> getAuthorities(
          Collection<Role> roles) {
 
            return getGrantedAuthorities(getPrivileges(roles));
        }
 
        private List<String> getPrivileges(Collection<Role> roles) {
 
            List<String> privileges = new ArrayList<>();
            List<Privilege> collection = new ArrayList<>();
            for (Role role : roles) {
                collection.addAll(role.getPrivileges());
            }
            for (Privilege item : collection) {
                privileges.add(item.getName());
            }
            return privileges;
        }
 
        private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges) {
            List<GrantedAuthority> authorities = new ArrayList<>();
            for (String privilege : privileges) {
                authorities.add(new SimpleGrantedAuthority(privilege));
            }
            return authorities;
        }
    }