org.springframework.security.core.userdetails.User无法强制转换为MyUserDetails

当我实现Spring安全性的User类时,我得到了类转换exception。 我想在MyUserDetails(id)中添加一些额外的细节,但我无法得到结果。

这个问题在这里得到了回答,但后来我得到了两个错误,不知道我在哪里失踪。

以下是我的代码:

SecurityConfig.java:

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("authenticationProvider") AuthenticationProvider authenticationProvider; @Autowired DataSource dataSource; @Autowired public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .passwordEncoder(passwordEncoder()) .usersByUsernameQuery( "select username,password, enabled from users where username=?") .authoritiesByUsernameQuery( "select username, role from user_roles where username=?"); } @Bean public PasswordEncoder passwordEncoder() { PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } @Override protected void configure(HttpSecurity http) throws Exception { http.headers().cacheControl().and().xssProtection().and() .frameOptions().and(); http.authorizeRequests() .antMatchers("/sadmin/**") .access("hasRole('ROLE_SADMIN')") .antMatchers("/admin/**") .access("hasRole('ROLE_ADMIN') or hasRole('ROLE_SADMIN')") .antMatchers("/") .access("hasRole('ROLE_ADMIN') or hasRole('ROLE_SADMIN') or hasRole('ROLE_USER')") .and().formLogin() .loginProcessingUrl("/j_spring_security_check") .loginPage("/login").failureUrl("/login?error") .usernameParameter("username").passwordParameter("password") .and().logout().logoutUrl("/j_spring_security_logout") .logoutSuccessUrl("/login?logout").and().exceptionHandling() .accessDeniedPage("/403").and().csrf(); // session management URL for reference // https://github.com/spring-projects/spring-security-javaconfig/blob/master/spring-security-javaconfig/src/test/groovy/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.groovy } 

MyUserDetails.java:

 public class MyUserDetails extends User { private int id; public MyUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); } // getter setter .... } 

CustomUserDetailsS​​ervice.java:

 @Service("userDetailsService") public class CustomUserDetailsService extends JdbcDaoImpl{ @Override protected List loadUsersByUsername(String username) { return getJdbcTemplate().query(super.getUsersByUsernameQuery(), new String[] { username }, new RowMapper() { public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException { String username = rs.getString("username"); String password = rs.getString("password"); boolean enabled = rs.getBoolean("enabled"); boolean accountNonExpired = rs.getBoolean("accountNonExpired"); boolean credentialsNonExpired = rs.getBoolean("credentialsNonExpired"); boolean accountNonLocked = rs.getBoolean("accountNonLocked"); int id = rs.getInt("id"); MyUserDetails myUserDetails = new MyUserDetails(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, AuthorityUtils.NO_AUTHORITIES); myUserDetails.setId(id); return myUserDetails; } }); } @Override protected UserDetails createUserDetails(String username, UserDetails userFromUserQuery, List combinedAuthorities) { String returnUsername = userFromUserQuery.getUsername(); if (!isUsernameBasedPrimaryKey()) { returnUsername = username; } final MyUserDetails myUserDetails = new MyUserDetails(returnUsername, userFromUserQuery.getPassword(), userFromUserQuery.isEnabled(), userFromUserQuery.isAccountNonExpired(), userFromUserQuery.isCredentialsNonExpired(), userFromUserQuery.isAccountNonLocked(), combinedAuthorities); myUserDetails.setId(((MyUserDetails) userFromUserQuery).getId()); return myUserDetails; } } 

获取MyUserDetails的代码:

 MyUserDetails userDetails = (MyUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

pom.xml中:

 4.0.5.RELEASE 4.0.1.RELEASE 

堆栈跟踪:

 SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/housing] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to com.esociety.dto.MyUserDetails] with root cause java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to com.esociety.dto.MyUserDetails at com.esociety.controller.LoginController.dashboard(LoginController.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852) at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:168) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Unknown Source) 

我有类似的“要求”,因为我的工作正常。 我的设置如下

 @Configuration protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder( passwordEncoder); } } 

我的猜测是你的问题在于auth.jdbcAuthentication() ,因为它将提供UserDetailsService实现,它返回核心安全User并且根本不使用你的实现。 见javadoc :

将JDBC身份validation添加到AuthenticationManagerBuilder并返回JdbcUserDetailsManagerConfigurer以允许自定义JDBC身份validation。 此方法还确保UserDetailsS​​ervice可用于getDefaultUserDetailsS​​ervice()方法。 请注意,其他UserDetailsS​​ervice可能会覆盖此UserDetailsS​​ervice作为默认值。

我已经采用了mkyong教程在MyUserDetails中添加其他数据(在我的案例中是电子邮件ID)。 请参考此链接获取完整代码,我只提供那些代码,因为我做了更改以获取电子邮件ID。

谢谢大家的时间和精力。 用户类

 @Entity @Table(name = "users", catalog = "test") public class User { private String username; private String password; private boolean enabled; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; private String emailId; private Set userRole = new HashSet(0); public User() { } public User(String username, String password, boolean enabled,boolean accountNonExpired,boolean accountNonLocked,boolean credentialsNonExpired, String emailId) { this.username = username; this.password = password; this.enabled = enabled; this.accountNonExpired = accountNonExpired; this.accountNonLocked = accountNonLocked; this.credentialsNonExpired = credentialsNonExpired; this.emailId = emailId; } public User(String username, String password, boolean enabled,boolean accountNonExpired,boolean accountNonLocked,boolean credentialsNonExpired, Set userRole,String emailId) { this.username = username; this.password = password; this.enabled = enabled; this.accountNonExpired = accountNonExpired; this.accountNonLocked = accountNonLocked; this.credentialsNonExpired = credentialsNonExpired; this.emailId = emailId; this.userRole = userRole; } @Id @Column(name = "username", unique = true, nullable = false, length = 45) public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } @Column(name = "password", nullable = false, length = 60) public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } @Column(name = "enabled", nullable = false) public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } @Column(name = "accountNonExpired", nullable = false) public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } @Column(name = "accountNonLocked", nullable = false) public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } @Column(name = "credentialsNonExpired", nullable = false) public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } @Column(name = "emailId", nullable = false) public String getEmailId() { return emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") public Set getUserRole() { return this.userRole; } public void setUserRole(Set userRole) { this.userRole = userRole; } } 

MyUserDetails类

 public class MyUserDetails extends User { private final String emailId; public MyUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked,String emailId, Collection authorities) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); // TODO Auto-generated constructor stub this.emailId = emailId; } public String getEmailId() { return emailId; } } 

MyUserDetailsS​​ervice类

 @Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Autowired private UserDao userDao; @Transactional(readOnly=true) @Override public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { com.mkyong.users.model.User user = userDao.findByUserName(username); List authorities = buildUserAuthority(user.getUserRole()); return buildUserForAuthentication(user, authorities); } private User buildUserForAuthentication(com.mkyong.users.model.User user, List authorities) { MyUserDetails myUserDetails = new MyUserDetails (user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isAccountNonLocked(), user.isCredentialsNonExpired(), user.getEmailId(),authorities); return myUserDetails; } private List buildUserAuthority(Set userRoles) { Set setAuths = new HashSet(); // Build user's authorities for (UserRole userRole : userRoles) { setAuths.add(new SimpleGrantedAuthority(userRole.getRole())); } List Result = new ArrayList(setAuths); return Result; } } 

安全配置类没有变化。 这与教程链接完全相同,但这是@sodik提供的改变JDBCAuthentication的提示

 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/admin/**") .access("hasRole('ROLE_ADMIN')").and().formLogin() .loginPage("/login").failureUrl("/login?error") .usernameParameter("username") .passwordParameter("password") .and().logout().logoutSuccessUrl("/login?logout") .and().csrf() .and().exceptionHandling().accessDeniedPage("/403"); } @Bean public PasswordEncoder passwordEncoder(){ PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } } 

AppConfig在此添加密码,因为密码未在教程链接中设置

 @EnableWebMvc @Configuration @ComponentScan({ "com.mkyong.*" }) @EnableTransactionManagement @Import({ SecurityConfig.class }) public class AppConfig { @Bean(name = "dataSource") public BasicDataSource dataSource() { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3036/test"); ds.setUsername("root"); ds.setPassword("password"); return ds; } }