Java 为什么在Spring Boot应用程序中UserDetailsService返回null?
一个简单的spring启动应用程序有一个自定义的UserDetails服务。Spring引导控制器由AngularJS应用程序调用,来自AngularJS应用程序的身份验证请求通过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? 该应用程序非常简
/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