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

Vaadin23+Spring Security实现数据库登录认证求助

实现基于数据库的UserDetailsService替代InMemoryUserDetailsManager

核心思路

Spring Security的UserDetailsService接口中,loadUserByUsername(String username)方法的参数就是登录表单提交的用户名——你无需手动获取,Spring Security会自动传递这个参数。你要做的就是注入已开发好的数据库操作类(仓库/服务),用这个参数查询用户实体,再转换为Spring Security所需的UserDetails对象即可。


步骤1:自定义UserDetailsService实现类

假设你已经有User实体类和对应的UserRepository(提供findByUsername查询方法),直接实现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 dbUser = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));

        // 将自定义User实体转换为Spring Security的UserDetails实例
        return User.builder()
                .username(dbUser.getUsername())
                .password(dbUser.getPassword()) // 注意:数据库中必须存加密后的密码
                .roles(dbUser.getRoles().toArray(new String[0])) // 假设roles是集合类型,转成数组
                .build();
    }
}

简化方案:让User实体直接实现UserDetails

如果不想每次都转换实体,可让你的User实体直接实现UserDetails接口,这样查询后可直接返回:

@Entity
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    @ElementCollection(fetch = FetchType.EAGER)
    private Set<String> roles;

    // 实现UserDetails的所有方法
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 将角色转换为Spring Security的权限对象
        return roles.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    // 以下方法根据你的业务需求调整,默认返回true即可
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    // 其他getter、setter方法
}

此时CustomUserDetailsService可简化为:

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

步骤2:在Spring Security配置中替换为自定义实现

修改你的Security配置类,注入自定义的CustomUserDetailsService,并替换掉InMemoryUserDetailsManager:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends VaadinWebSecurityConfigurerAdapter {

    private final CustomUserDetailsService userDetailsService;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        // 你的其他Vaadin/Spring Security配置(比如允许访问的路径等)
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder()); // 必须配置密码编码器,对应数据库密码的加密规则
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 示例用BCrypt加密,根据你实际的加密方式选择
        return new BCryptPasswordEncoder();
    }
}

关键注意事项

  1. 密码必须加密存储:数据库中不能存明文密码,创建用户时必须用PasswordEncoder加密后再存入。
  2. 仓库方法确保存在:UserRepository中必须有findByUsername(String username)方法,Spring Data JPA可通过方法名自动生成实现,无需手写SQL。

内容的提问来源于stack exchange,提问作者Anil Patel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 10:33:11