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

Spring Security的User类能否直接搭配CrudRepository使用?求替代继承的方案

Fixing "It's not a managed type" with Spring Security's User and Spring Data JPA

Hey there! Let's tackle this frustrating error you're running into. The root cause is straightforward: Spring Security's org.springframework.security.core.userdetails.User class isn't a JPA managed entity—it lacks the @Entity annotation, so Spring Data JPA can't recognize it as a type to persist or query against. And just to clarify: the User class is actually final, so you can't even inherit from it (that "inheritance solution" you found might have been referring to implementing the UserDetails interface instead, which is a different approach).

Here are two cleaner, more maintainable solutions that don't force you to hack around the User class:

This approach keeps your database model and security model decoupled, making it easier to extend either side later on.

  1. Create a custom JPA entity to map your Derby database table:
@Entity
@Table(name = "app_users") // Avoid "users" as it may be a reserved word in some databases
public class AppUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String username;
    
    @Column(nullable = false)
    private String password;
    
    private boolean enabled;
    
    // Add extra fields like email, full name as needed
    // Getters, setters, and constructors here
}
  1. Create a Spring Data Repository for your entity:
public interface AppUserRepository extends CrudRepository<AppUser, Long> {
    Optional<AppUser> findByUsername(String username);
}
  1. Implement a custom UserDetailsService to convert your AppUser entity into Spring Security's User when needed:
@Service
public class AppUserDetailsService implements UserDetailsService {
    private final AppUserRepository appUserRepository;

    public AppUserDetailsService(AppUserRepository appUserRepository) {
        this.appUserRepository = appUserRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        AppUser appUser = appUserRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
        
        // Build the Spring Security User object from your entity
        return User.withUsername(appUser.getUsername())
                .password(appUser.getPassword())
                .enabled(appUser.isEnabled())
                .authorities("ROLE_USER") // Replace with actual permissions from your DB if needed
                .build();
    }
}

Option 2: Implement UserDetails Directly in Your JPA Entity

If you prefer a more streamlined approach (no conversion layer), you can make your custom entity implement Spring Security's UserDetails interface. This way, it's both a JPA managed type and a valid security user.

  1. Create the combined entity:
@Entity
@Table(name = "app_users")
public class AppUser implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String username;
    
    @Column(nullable = false)
    private String password;
    
    private boolean enabled;
    
    // Store authorities using @ElementCollection for a list of permissions
    @ElementCollection(fetch = FetchType.EAGER)
    private List<String> authorities;

    // Implement all UserDetails methods
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

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

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

    @Override
    public boolean isAccountNonExpired() {
        return true; // Adjust based on your business rules
    }

    @Override
    public boolean isAccountNonLocked() {
        return true; // Adjust based on your business rules
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true; // Adjust based on your business rules
    }

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

    // Getters, setters, and constructors here
}
  1. Create the Repository:
public interface AppUserRepository extends CrudRepository<AppUser, Long> {
    Optional<AppUser> findByUsername(String username);
}
  1. Update your UserDetailsService (simpler now, no conversion needed):
@Service
public class AppUserDetailsService implements UserDetailsService {
    private final AppUserRepository appUserRepository;

    public AppUserDetailsService(AppUserRepository appUserRepository) {
        this.appUserRepository = appUserRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return appUserRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
    }
}

Both options will resolve the "It's not a managed type" error, and they're far more maintainable than trying to force Spring Security's User class into a role it wasn't designed for. Pick the one that fits your POC's needs—Option 1 is great if you think you'll need to expand your database model independently of security later, while Option 2 is perfect for a simpler, more tightly integrated setup.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:21:25