Java 为什么在Spring Boot应用程序中UserDetailsService返回null?

Java 为什么在Spring Boot应用程序中UserDetailsService返回null?,java,spring,spring-mvc,spring-security,spring-boot,Java,Spring,Spring Mvc,Spring Security,Spring Boot,一个简单的spring启动应用程序有一个自定义的UserDetails服务。Spring引导控制器由AngularJS应用程序调用,来自AngularJS应用程序的身份验证请求通过/userurl模式发送到后端。但是登录请求导致控制器日志指示控制器没有找到/userurl模式,因此UserDetailsService返回null需要对下面的代码进行哪些特定更改,以使后端/userurl模式的客户端请求能够找到控制器方法,从而正确实例化自定义UserDetailsService? 该应用程序非常简

一个简单的spring启动应用程序有一个自定义的UserDetails服务。Spring引导控制器由AngularJS应用程序调用,来自AngularJS应用程序的身份验证请求通过
/user
url模式发送到后端。但是登录请求导致控制器日志指示控制器没有找到
/user
url模式,因此UserDetailsService返回null需要对下面的代码进行哪些特定更改,以使后端
/user
url模式的客户端请求能够找到控制器方法,从而正确实例化自定义
UserDetailsService

该应用程序非常简单,控制器的代码不到200行

控制器的代码为:

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

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

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

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver slr = new SessionLocaleResolver();
        slr.setDefaultLocale(Locale.US);
        return slr;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        lci.setParamName("lang");
        return lci;
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }


    @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("/index.html", "/", "/login", "/message", "/home")
                    .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;
        }
    }

    @Service
    class Users implements UserDetailsService {

        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) {
                return null;
            }
            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);
        }

    }

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

    @Entity
    class User {
        @GeneratedValue
        @Id
        private Long iduser;
        private String name;
        private String password;
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
        private Collection<SessionLog> sessionLogCollection;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPassword() {
            return password;
        }

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

    @Entity
    class SessionLog {

        @GeneratedValue
        @Id
        private Long id;
        private String sessionid;
        @ManyToOne(optional = true)
        @JoinColumn(name = "iduser")
        private User user;

        public String getSessionid() {
            return sessionid;
        }
    }

}

找到了控制器的方法。问题在于此代码:

if (user == null) {
    return null;
}
您可以在日志消息中清楚地看到:

Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null, which is an interface contract violation
UserDetailsService实现中不允许返回null


因此,请检查您的数据库中是否有管理员用户的条目,删除
return null
,并抛出
UsernameNotFoundException

鉴于否决票的数量和关闭其他帖子的3票,我将其删除。我认为问题在于我发布的控制器之外有一个冗余的
用户
实体,另外还有一个外部的
角色
实体,它解释了生成的数据库模式中的那些冗余表。复制项目,剥离应用程序中所有无关的内容并删除数据库,然后启动剥离的副本会导致应用程序正确验证。谢谢你的帮助。我会在生活的另一个方面帮助别人,这对我来说更容易。
Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null, which is an interface contract violation