Authentification avec Spring Security et Angular
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:
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:
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:
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:
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:
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;
}
} |