Spring Boot应用登录与注册时出现403 Forbidden错误求助
Spring Boot认证与注册接口返回403 Forbidden问题排查
问题描述
在Spring Boot应用中,验证用户osamazaza200(正确密码test123)的登录流程时,尽管凭据正确,认证仍失败并返回403 Forbidden错误。调用/api/auth/signup接口注册用户时也出现相同错误。
复现步骤
- 创建用户:用户名
osamazaza200,密码test123(已哈希存储在数据库) - 调用
/signin接口登录,返回403 Forbidden - 发起POST请求
http://localhost:8080/api/auth/signup,请求体如下,同样返回403:
{ "name": "Loyasl Essa", "username": "testrer", "email": "test123@gmail.com", "password": "12345678" }
相关代码与配置
1. Security Config类
@Configuration @EnableMethodSecurity public class SecurityConfig { private UserDetailsService userDetailsService; public SecurityConfig(UserDetailsService userDetailsService){ this.userDetailsService = userDetailsService; } @Bean public static PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { return configuration.getAuthenticationManager(); } @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET, "/api/**").permitAll() .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() ); return http.build(); } }
2. AuthController
package com.muhammedessa.securityapicrud.controllers; @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; @Autowired private PasswordEncoder passwordEncoder; @PostMapping("/signin") public ResponseEntity<String> authenticateUser(@RequestBody LoginDto loginDto){ Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken( loginDto.getUsernameOrEmail(), loginDto.getPassword())); SecurityContextHolder.getContext().setAuthentication(authentication); return new ResponseEntity<>("User signed-in successfully!.", HttpStatus.OK); } @PostMapping("/signup") public ResponseEntity<?> registerUser(@RequestBody SignUpDto signUpDto){ if(userRepository.existsByUsername(signUpDto.getUsername())){ return new ResponseEntity<>("Username is already taken!", HttpStatus.BAD_REQUEST); } if(userRepository.existsByEmail(signUpDto.getEmail())){ return new ResponseEntity<>("Email is already taken!", HttpStatus.BAD_REQUEST); } User user = new User(); user.setName(signUpDto.getName()); user.setUsername(signUpDto.getUsername()); user.setEmail(signUpDto.getEmail()); user.setPassword(passwordEncoder.encode(signUpDto.getPassword())); Role roles = roleRepository.findByName("ROLE_ADMIN").get(); user.setRoles(Collections.singleton(roles)); userRepository.save(user); return new ResponseEntity<>("User registered successfully", HttpStatus.OK); } }
3. 其余核心代码(Login DTO/SignUp DTO/实体类/Repository/CustomUserDetailsService)
(代码结构与原提问一致,此处省略重复内容)
4. Application Properties
spring.application.name=APIDemo spring.datasource.url=jdbc:mysql://127.0.0.1:3306/usersdb?useSSL=false spring.datasource.username=root spring.datasource.password= spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect spring.jpa.hibernate.ddl-auto = update logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type=TRACE
问题排查与解决方案
1. 关闭CSRF防护(核心解决方法)
Spring Security默认开启CSRF防护,对POST/PUT/DELETE等非GET请求强制验证CSRF Token,而你的API接口未处理该逻辑,导致请求被拦截返回403。修改SecurityConfig:
@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) // 新增该行关闭CSRF .authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET, "/api/**").permitAll() .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() ); return http.build(); }
2. 验证密码哈希一致性
若手动添加数据库用户,需确保密码是通过BCryptPasswordEncoder生成的哈希值。可通过以下代码生成正确哈希:
PasswordEncoder encoder = new BCryptPasswordEncoder(); System.out.println(encoder.encode("test123"));
将输出结果替换数据库中用户的密码字段。
3. 完善角色存在性校验
注册接口中直接调用roleRepository.findByName("ROLE_ADMIN").get(),若数据库无该角色会抛出异常,建议添加非空判断:
Optional<Role> roleOpt = roleRepository.findByName("ROLE_ADMIN"); if(roleOpt.isEmpty()){ return new ResponseEntity<>("系统角色缺失", HttpStatus.INTERNAL_SERVER_ERROR); } Role roles = roleOpt.get();
4. 确认权限规则顺序
当前配置中/api/auth/**的放行规则在anyRequest().authenticated()之前,顺序正确,无需调整。
验证步骤
- 修改SecurityConfig后重启应用
- 重新测试注册、登录接口
- 若仍失败,检查数据库中用户密码哈希值、角色数据是否正确
内容的提问来源于stack exchange,提问作者Android World
相关产品推荐
相关产品推荐

