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

基于Spring Security 6的在线点餐系统认证授权配置求助

Spring Security 6 认证授权配置修正方案

一、实体类校验(User & UserRole)

确保实体关联与角色名称符合Spring Security规范:

  • User实体需通过@ManyToMany关联UserRole,且提供获取权限集合的方法
  • UserRole的角色名称字段需存储ROLE_SYSADMIN、ROLE_ADMIN、ROLE_CUSTOMER这类带ROLE_前缀的值

示例User实体核心代码:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<UserRole> roles;

    // getter/setter
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles.stream()
                .map(role -> new SimpleGrantedAuthority(role.getRoleName()))
                .collect(Collectors.toList());
    }
}

二、自定义UserDetails实现(HiruezUserDetails)

严格实现UserDetails接口,确保各方法返回符合业务逻辑的状态:

public class HiruezUserDetails implements UserDetails {
    private final User user;

    public HiruezUserDetails(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return user.getAuthorities();
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true; // 可根据业务添加账号过期字段调整
    }

    @Override
    public boolean isAccountNonLocked() {
        return true; // 可根据业务添加账号锁定字段调整
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true; // 可根据业务添加凭证过期字段调整
    }

    @Override
    public boolean isEnabled() {
        return true; // 可根据业务添加账号启用状态字段调整
    }
}

三、自定义UserDetailsService实现

确保从数据库正确查询用户及关联角色,处理用户不存在的异常:

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
        return new HiruezUserDetails(user);
    }
}

四、SecurityConfig配置(Spring Security 6)

适配Spring Security 6的链式配置方式,注意密码编码器与权限规则:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private final CustomUserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;

    public SecurityConfig(CustomUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/sysadmin/**").hasRole("SYSADMIN")
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .requestMatchers("/customer/**", "/login", "/register").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .defaultSuccessUrl("/home")
                        .permitAll()
                )
                .logout(logout -> logout
                        .logoutSuccessUrl("/login?logout")
                        .permitAll()
                );

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 必须配置,明文密码无法通过认证
    }
}

五、常见问题排查

  • 数据库中用户密码必须通过BCryptPasswordEncoder加密存储,明文密码会导致认证失败
  • 使用hasRole时,Spring Security会自动添加ROLE_前缀,需确保数据库角色名包含该前缀;若不想用前缀,可改用hasAuthority并完全匹配角色名
  • 确认UserRepository的findByUsername方法正确实现,且User与UserRole的关联使用FetchType.EAGER,避免懒加载导致角色数据无法获取
  • 确保使用Spring Boot 3.x版本,Spring Security 6仅适配Spring Boot 3+

内容的提问来源于stack exchange,提问作者Đào Kim Dương

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 23:47:22