【发布时间】:2020-06-21 13:59:45
【问题描述】:
我正在使用 spring boot-angular 应用程序实现 spring security。在我的用户控制器中,我在以下 url 上映射了一个方法:/api/user/login 来连接用户,获取用户信息,识别用户并检查他是否在数据库中注册。当我启动 Angular 应用程序时,会触发 url: http://localhost:8080/api/user/login 并出现 405 状态错误。我有几个问题
1) url:http://localhost:8080/api/user/login, 在开始时被触发是否正常?我不明白为什么。我希望用户的连接专门用于弹出表单(触发http://localhost:8080/api/user/login url)
2)如果正常的话,这样一个url的目的是什么,我该如何用这个url实现端点控制器?
3) 在我的 Angular 应用程序中,我将 proxy.config.json 设置如下
{
"/api/*": {
"target": {
"host": "localhost",
"protocol": "http:",
"port": 8080
},
"secure": false,
"changeOrigin": true,
"logLevel": "info"
}
}
将每个 localhost:42OO/api 重定向到 localhost:8080/api。为此,在前端部分,我使用“ng serve --proxy-config proxy.config.json”命令启动应用程序。
当“http://localhost:8080/api/user/login”被触发时,我有以下错误信息:
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/api/user/login. Raison : l’en-tête CORS « Access-Control-Allow-Origin » est manquant.
Blocking of a multi-origin request (Cross-Origin Request): the "Same Origin" policy does not allow consulting the remote resource located on http: // localhost: 8080 / api / user / login. Reason: The CORS header "Access-Control-Allow-Origin" is missing.
那么,如何处理呢?
这里是spring安全问题的配置
文件 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;
}
}
用户控制器UserController.java
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;
}
InitialDataLoader.java 文件
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;
}
}
UserDetailsService 实现:
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;
}
}
【问题讨论】:
-
为 CORS 添加了答案。对于其他问题,请分享您的 Angular 代码(为什么在开始时获取 URL)。谢谢。
标签: angular spring-boot spring-security