java - query - org.springframework.security.core.userdetails.User no se puede convertir a MyUserDetails
user details spring security (2)
He tomado el tutorial de mkyong para agregar datos adicionales en MyUserDetails (en mi caso, correo electrónico). Consulte este link para obtener el código completo. Estoy colocando solo los códigos en los que hice cambios para obtener la identificación del correo electrónico.
Gracias a todos por su tiempo y esfuerzo. Clase de usuario
@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> userRole = new HashSet<UserRole>(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> 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<UserRole> getUserRole() {
return this.userRole;
}
public void setUserRole(Set<UserRole> userRole) {
this.userRole = userRole;
}
}
Clase 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<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired,
credentialsNonExpired, accountNonLocked, authorities);
// TODO Auto-generated constructor stub
this.emailId = emailId;
}
public String getEmailId() {
return emailId;
}
}
MyUserDetailsService Class
@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<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(com.mkyong.users.model.User user, List<GrantedAuthority> authorities) {
MyUserDetails myUserDetails = new MyUserDetails (user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isAccountNonLocked(), user.isCredentialsNonExpired(), user.getEmailId(),authorities);
return myUserDetails;
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user''s authorities
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
}
Clase de configuración de seguridad no hay cambio en esto. Este es exactamente el mismo que el enlace del tutorial, pero fue una sugerencia de @sodik para cambiar la autenticación JDBCA.
@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 agregando contraseña en esto porque la contraseña no se configuró en el enlace del tutorial
@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;
}
}
Recibo la excepción de conversión de clase cuando implemento la clase de usuario de seguridad de Spring. Quiero agregar algunos detalles adicionales en MyUserDetails (id) pero no puedo obtener el resultado.
Esta pregunta se responde here pero luego me estoy equivocando. No sé dónde me estoy perdiendo.
A continuación se muestra mi código:
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<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired,
credentialsNonExpired, accountNonLocked, authorities);
}
// getter setter ....
}
CustomUserDetailsService.java:
@Service("userDetailsService")
public class CustomUserDetailsService extends JdbcDaoImpl{
@Override
protected List<UserDetails> loadUsersByUsername(String username) {
return getJdbcTemplate().query(super.getUsersByUsernameQuery(), new String[] { username },
new RowMapper<UserDetails>() {
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<GrantedAuthority> 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;
}
}
Código para obtener MyUserDetails:
MyUserDetails userDetails = (MyUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
pom.xml:
<org.springframework.version>4.0.5.RELEASE</org.springframework.version>
<spring.security.version>4.0.1.RELEASE</spring.security.version>
Stacktrace:
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)
Tengo "requisitos" similares a los de usted y para mi está funcionando bien. Mi configuración es la siguiente
@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);
}
}
Mi conjetura es que su problema es con auth.jdbcAuthentication()
ya que proporcionará la implementación de UserDetailsService
que devuelve al User
seguridad principal y no usa su implementación en absoluto. Ver javadoc :
Agregue la autenticación JDBC al AuthenticationManagerBuilder y devuelva un JdbcUserDetailsManagerConfigurer para permitir la personalización de la autenticación JDBC. Este método también garantiza que un UserDetailsService esté disponible para el método getDefaultUserDetailsService (). Tenga en cuenta que UserDetailsService''s adicional puede anular este UserDetailsService como predeterminado.