无法自动装配自定义 UserDetails [英] Unable to autowire custom UserDetails

查看:41
本文介绍了无法自动装配自定义 UserDetails的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

A Spring Boot app has a custom UserDetails. Everything works properly when all the app does is authenticate existing users from a database with the User class. However, problems emerge when I try to make changes so that people can create new user accounts through the app GUI. Specifically, changing the custom UserDetailsService to become a UserDetailsManager required changing the User class to explicitly implement UserDetails, which in turn is now causing Spring to be unable to compile a jar when I type java -jar target/modular-0.0.1-SNAPSHOT.jar in the terminal from the root directory of the app.

核心错误信息是:

    java.lang.IllegalArgumentException: 
    Not an managed type: interface org.springframework.security.core.userdetails.UserDetails

需要对以下代码进行哪些具体更改才能使 Spring 能够使用自定义 UserDetailsUserDetailsManager 编译应用程序?

What specific changes need to be made to the code below in order to enable Spring to be able to compile the app with the custom UserDetails and UserDetailsManager?

这里是应用程序中核心类的代码,其中包括 Spring Security 配置:

Here is the code for the core class in the app, which includes the Spring Security configuration:

@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);
    }

}

Users.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;
    }

}  

User.java 是:

@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;
    }
}

WebLeadRepository.java 是:

public interface WebLeadRepository extends JpaRepository<WebLead, Long> {

    List<WebLead> findByLastname(String lastName);
    List<WebLead> findBySessionid(String sid);
    WebLead findByIdlead(Long idl);
}

此帖子的完整堆栈跟踪太长,但 我已将完整堆栈跟踪上传到文件共享站点,您可以点击此链接查看.此外,堆栈跟踪中的根本原因总结如下:

The complete stack trace is too long for this posting, but I have uploaded the complete stack trace to a file sharing site, which you can view by clicking on this link. In addition, the root cause in the stack trace is summarized below as follows:

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)

推荐答案

首先,您需要修复存储库的映射,您尝试持久化的对象是 User 而不是 用户详细信息.Spring Data JPA 需要此信息,以便它可以扫描实体并创建必要的绑定.

First you need to fix the mapping for your repository, the object you are trying to persist is a User not a UserDetails. Spring Data JPA needs this information so that it can scan the entity and create the necessary bindings.

@Repository
interface UserRepository extends CrudRepository<User, Long> {
    User findByName(String name);
}

现在您的自定义UserDetailsManagerUsers 中将出现编译问题.由于所有方法都采用 UserDetails 对象,而不是您的 User 对象,而后者正是您的 UserRepository 所期望的对象.要解决这个问题,只需在将参数传递给 UserRepository 之前将参数强制转换为 User.

Now you will have a compilation issue in your custom UserDetailsManager class Users. As all the methods take a UserDetails object and not your User object which is the one expected by your UserRepository. To fix this simply cast the argument to User before passing it to the UserRepository.

@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);
}

这篇关于无法自动装配自定义 UserDetails的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆