使用正确账号密码仍出现401未授权——Spring Boot Security认证问题
问题分析
你的代码存在三个关键问题导致认证失败:
- 缺少
PasswordEncoderBean:Spring Security 2.x及以后版本要求必须显式提供密码编码器,否则无法完成密码校验,默认用户user的密码验证也会失败。 - 注册接口被拦截:当前配置要求所有请求都必须认证,但
POST /user是注册接口,需要允许匿名访问,否则连新用户都无法创建。 - 未配置用户信息来源:如果使用默认用户,需要确保其密码使用对应的编码器处理,或者自定义用户查询逻辑。
修复步骤
1. 完善Security配置
修改SecurityConfig,添加密码编码器Bean,并放开注册接口的匿名访问权限:
package com.api.business_products_management.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests() // 允许注册接口匿名访问 .requestMatchers("/user").permitAll() // 其他所有请求需要认证 .anyRequest().authenticated() .and() .httpBasic(); return http.build(); } }
2. 优化Controller的密码编码器使用
将密码编码器注入到Controller中使用,而非每次创建新实例:
package com.api.business_products_management.controllers; import com.api.business_products_management.dtos.UserDto; import com.api.business_products_management.models.UserModel; import com.api.business_products_management.services.UserService; import jakarta.validation.Valid; import org.springframework.beans.BeanUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; @RestController @CrossOrigin(origins = "*", maxAge = 3600) @RequestMapping("/user") public class UserController { final UserService userService; final PasswordEncoder passwordEncoder; // 注入PasswordEncoder public UserController(UserService userService, PasswordEncoder passwordEncoder) { this.userService = userService; this.passwordEncoder = passwordEncoder; } @PostMapping public ResponseEntity<Object> saveUser(@RequestBody @Valid UserDto userDto) { var userModel = new UserModel(); BeanUtils.copyProperties(userDto, userModel); userModel.setPassword(passwordEncoder.encode(userModel.getPassword())); return ResponseEntity.status(HttpStatus.CREATED).body(userService.save(userModel)); } }
3. 配置默认用户(可选)
如果需要继续使用Spring Security的默认用户,可在SecurityConfig中添加内存用户配置:
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.provisioning.InMemoryUserDetailsManager; // 在SecurityConfig中添加该Bean @Bean public InMemoryUserDetailsManager userDetailsService() { UserDetails user = User.withUsername("user") .password(passwordEncoder().encode("your-custom-password")) // 设置自定义默认密码 .roles("USER") .build(); return new InMemoryUserDetailsManager(user); }
注:自定义用户后,Spring Boot不会再自动生成随机密码,需手动设置密码。
测试验证
- 重启应用后,先调用
POST /user接口创建新用户(无需认证) - 使用创建的用户或配置的默认用户,通过Postman的"Basic Auth"方式输入用户名密码,访问其他需要认证的接口,即可正常通过授权。
内容的提问来源于stack exchange,提问作者Routfin
相关产品推荐
相关产品推荐

