You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()之前,顺序正确,无需调整。

验证步骤

  1. 修改SecurityConfig后重启应用
  2. 重新测试注册、登录接口
  3. 若仍失败,检查数据库中用户密码哈希值、角色数据是否正确

内容的提问来源于stack exchange,提问作者Android World

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:58:23