Java 无法自动关联自定义用户详细信息

Java 无法自动关联自定义用户详细信息,java,spring,spring-mvc,spring-security,spring-boot,Java,Spring,Spring Mvc,Spring Security,Spring Boot,Spring启动应用程序具有自定义的UserDetails。当应用程序所做的只是使用User类对数据库中的现有用户进行身份验证时,一切都正常工作。但是,当我尝试进行更改,以便人们可以通过应用程序GUI创建新的用户帐户时,就会出现问题。具体而言,将自定义的UserDetails服务更改为UserDetailsManager需要将User类更改为显式的实现UserDetails,当我从应用程序的根目录在终端中键入java-jar-target/modular-0.0.1-SNAPSHOT.jar时,

Spring启动应用程序具有自定义的UserDetails。当应用程序所做的只是使用User类对数据库中的现有用户进行身份验证时,一切都正常工作。但是,当我尝试进行更改,以便人们可以通过应用程序GUI创建新的用户帐户时,就会出现问题。具体而言,将自定义的
UserDetails服务
更改为
UserDetailsManager
需要将
User
类更改为显式的
实现UserDetails
,当我从应用程序的根目录在终端中键入
java-jar-target/modular-0.0.1-SNAPSHOT.jar
时,这反过来又导致Spring无法编译jar

核心错误消息是:

    java.lang.IllegalArgumentException: 
    Not an managed type: interface org.springframework.security.core.userdetails.UserDetails
为了使Spring能够使用自定义的
UserDetails
UserDetailsManager
编译应用程序,需要对下面的代码进行哪些具体更改?

以下是应用程序中核心类的代码,其中包括Spring安全配置:

@SpringBootApplication
@Controller
@EnableJpaRepositories(basePackages = "demo", considerNestedRepositories = true)
public class UiApplication extends WebMvcConfigurerAdapter {

    @Autowired
    private WebLeadRepository myrepo;   

    @Autowired
    private Users users;//duplicate from AuthenticationSecurity internal class below. Remove one?

    // Match everything without a suffix (so not a static resource)
    @RequestMapping(value = "/{[path:[^\\.]*}")
    public String redirect() {
        // Forward to home page so that route is preserved.
        return "forward:/";
    }

    @RequestMapping("/user")
    @ResponseBody
    public Principal user(Principal user) {
        return user;
    }

//lots of other @RequestMapping @ResponseBody url handling methods

    public static void main(String[] args) {
        SpringApplication.run(UiApplication.class, args);
    }

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Configuration
    protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {

        @Autowired
        private Users users;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(users);
        }
    }

    @SuppressWarnings("deprecation")
    @Configuration
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    @EnableWebMvcSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.httpBasic().and().authorizeRequests()
                .antMatchers("/sign-up").permitAll()
                .antMatchers("/index.html", "/", "/login", "/something*") 
                .permitAll().anyRequest().authenticated().and().csrf()
                .csrfTokenRepository(csrfTokenRepository()).and()
                .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
        }

        private Filter csrfHeaderFilter() {
            return new OncePerRequestFilter() {
                @Override
                protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                        if (csrf != null) {
                            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                            String token = csrf.getToken();
                            if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                                cookie = new Cookie("XSRF-TOKEN", token);
                                cookie.setPath("/");
                                response.addCookie(cookie);
                        }
                    }
                    filterChain.doFilter(request, response);
                }
            };
        }

        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
            repository.setHeaderName("X-XSRF-TOKEN");
            return repository;
        }
    }

    @Repository//This repository is what Spring cannot seem to create in the stack trace
    interface UserRepository extends CrudRepository<UserDetails, Long> {
        User findByName(String name);
    }

}
User.java
是:

@Service
class Users implements UserDetailsManager {

    private UserRepository repo;

    @Autowired
    public Users(UserRepository repo) {this.repo = repo;}

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = repo.findByName(username);
        if (user == null) {throw new UsernameNotFoundException("Username was not found. ");}
        List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
        if (username.equals("admin")) {auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");}
        String password = user.getPassword();
        return new org.springframework.security.core.userdetails.User(username, password, auth);
    }

    @Override
    public void createUser(UserDetails user) {// TODO Auto-generated method stub
        repo.save(user);
    }

    @Override
    public void updateUser(UserDetails user) {// TODO Auto-generated method stub
        repo.save(user);
    }

    @Override
    public void deleteUser(String username) {// TODO Auto-generated method stub
        User deluser = (User)this.loadUserByUsername(username);
        repo.delete(deluser);
    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {
        // TODO Auto-generated method stub
    }

    @Override
    public boolean userExists(String username) {
        // TODO Auto-generated method stub
        return false;
    }

}  
@Entity
class User implements UserDetails{

    @GeneratedValue
    @Id
    private Long iduser;
    private String name;//valid email address only
    private String password;
//lots of other properties that model all the things the User does in the app

    //getters and setters
    public String getName() {return name;}//valid email address
    public void setName(String name) {this.name = name;}//valid email address

    public String getPassword() {return password;}
    public void setPassword(String password) {this.password = password;}

    //LOTS OF OTHER GETTERS AND SETTERS OMITTED HERE, THAT MANAGE MANY CUSTOM PROPERTIES

    // Also, All the following are for implementing UserDetails
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {// TODO Auto-generated method stub
        return null;
    }
    @Override
    public String getUsername() {// TODO Auto-generated method stub
        return null;
    }
    @Override
    public boolean isAccountNonExpired() {// TODO Auto-generated method stub
        return false;
    }
    @Override
    public boolean isAccountNonLocked() {// TODO Auto-generated method stub
        return false;
    }
    @Override
    public boolean isCredentialsNonExpired() {// TODO Auto-generated method stub
        return false;
    }
    @Override
    public boolean isEnabled() {// TODO Auto-generated method stub
        return false;
    }
}
public interface WebLeadRepository extends JpaRepository<WebLead, Long> {

    List<WebLead> findByLastname(String lastName);
    List<WebLead> findBySessionid(String sid);
    WebLead findByIdlead(Long idl);
}
完整的堆栈跟踪对于此发布来说太长,但是。此外,堆栈跟踪中的根本原因总结如下:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uiApplication.UserRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: interface org.springframework.security.core.userdetails.UserDetails
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
    ... 38 more
Caused by: java.lang.IllegalArgumentException: Not an managed type: interface org.springframework.security.core.userdetails.UserDetails
    at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
    at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
    at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:67)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:152)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:99)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:81)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:185)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:251)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:237)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
原因:org.springframework.beans.factory.BeanCreationException:创建名为“uiApplication.UserRepository”的bean时出错:调用init方法失败;嵌套异常是java.lang.IllegalArgumentException:不是托管类型:interface org.springframework.security.core.userdetails.userdetails
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
位于org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
位于org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
位于org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
位于org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
位于org.springframework.beans.factory.support.DefaultListableBeanFactory.FindAuthories(DefaultListableBeanFactory.java:1192)
位于org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
位于org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
位于org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
位于org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 38多
原因:java.lang.IllegalArgumentException:非托管类型:interface org.springframework.security.core.userdetails.userdetails
位于org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
位于org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation。(JpaMetamodelEntityInformation.java:68)
位于org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:67)
位于org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:152)
位于org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetPository(JpaRepositoryFactory.java:99)
位于org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetPository(JpaRepositoryFactory.java:81)
位于org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:185)
位于org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:251)
位于org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertieSet(RepositoryFactoryBeanSupport.java:237)
位于org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.AfterPropertieSet(JpaRepositoryFactoryBean.java:92)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)

您可能需要UserDetails接口上的@MappedSuperClass注释,否则hibernate将不知道如何持久化实现该接口的任何内容。

我采用了拥有两个类的方法:一个用户实体和一个自定义用户详细信息类。我编写了一个helper方法来从(实体)用户生成CustomUserDetails。这样,Spring对象和实体对象之间就有了分离/区别

编辑:代码

自定义用户详细信息:

public class CustomUser extends User implements UserDetails, CredentialsContainer {
用户实体:

@Entity
@Table(name="users")
public class User {
这一切都由自定义用户详细信息服务连接:

public class CustomUserDetailsService extends JdbcUserDetailsManager implements UserDetailsService {    
在loadByUserName(您必须在CustomUserDetailsService中实现的方法之一)中,我从用户实体创建CustomUserDetails:

CustomUser customUser = user.getUserDetails();
请参阅,这解释了错误“不是托管类型”这是stacktrace中的输出。Spring数据的贡献者Oliver Gierke指出,可能存在与JPA实体相关的包问题,但是只有当Spring启动应用程序在发现应用程序中的所有类时,这才是您的问题,因此它可能无法回答您的问题

另一种可能性是,奥利弗·吉尔克,w
@Repository
interface UserRepository extends CrudRepository<User, Long> {
    User findByName(String name);
}
@Override
public void createUser(UserDetails user) {// TODO Auto-generated method stub
    repo.save((User) user);
}

@Override
public void updateUser(UserDetails user) {// TODO Auto-generated method stub
    repo.save((User) user);
}