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
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".
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" } }
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:
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
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 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 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; }
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
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; } }
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; } }
Partager