2016-04-20 7 views
0

Ich muss einige zusätzliche Informationen über den Benutzer speichern, um übermäßige Datenbankanforderungen auszuschließen. So wie ich es verstanden habe, muss ich:
1) Override UserDetails Schnittstelle. In dieser Implementierung speichern Sie alle zusätzlichen Informationen, die ich brauche.
2) Überschreiben Sie die UserDetailsService-Schnittstelle. In loadUserByUsername (String email) muss ich meine Implementierung der UserDetails Klasse zurückgeben. Danach kann ich dieses Objekt mit der getPrincipal() Methode bekommen.Wie behebt man die Implementierung von ClassCastException for UserDetails?

Bitte korrigieren Sie mich, wenn ich einen Fehler in 1) oder 2) gemacht habe. Also welches Problem habe ich? Eigentlich, wenn ich versuche, getPrincipal() gibt es org.springframework.security.core.userdetails.User Implementierung der UserDetails-Schnittstelle, die ich nicht in der Lage bin zu LoggedUser zu werfen, weil, logisch, dass ClassCastException auftritt.

Vielen Dank im Voraus für jede Hilfe. P.S. Ich habe auch versucht, Benutzerklasse zu erweitern, hatte aber das gleiche Ergebnis.

AuthUserDetailsService (UserDetailsService Implementierung):

@Service 
public class CustomUserDetailsService implements UserDetailsService { 

    @Autowired 
    public Storages storage; 

    @Override 
    public LoggedUser loadUserByUsername(String email) 
     throws UsernameNotFoundException { 

    boolean enabled = true; 
    boolean accountNonExpired = true; 
    boolean credentialsNonExpired = true; 
    boolean accountNonLocked = true; 

    milkiv.easyword.models.User user = getUserDetails(email); 
    if (user != null) { 
     LoggedUser userdetails = new LoggedUser(
      user, 
      enabled, 
      accountNonExpired, 
      credentialsNonExpired, 
      accountNonLocked, 
      getAuthorities(1) 
     ); 
     return userdetails; 
    } else { 
     throw new UsernameNotFoundException(email); 
    } 
    } 

    public List<GrantedAuthority> getAuthorities(int role) { 

    List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); 
    if (role == 1) { 
     authList.add(new SimpleGrantedAuthority("ROLE_ADMIN")); 
    } else if (role == 2) { 
     authList.add(new SimpleGrantedAuthority("ROLE_USER")); 
    } 
    return authList; 
    } 

    private milkiv.easyword.models.User getUserDetails(String email) { 
    milkiv.easyword.models.User user = storage.uSM.findByEmail(email); 
    return user; 
    } 
    } 

LoggedUser (Userdetails Implementierung):

public class LoggedUser implements UserDetails{ 

    User user = new User(); 
    private boolean enabled; 
    private boolean accountNonExpired; 
    private boolean credentialsNonExpired; 
    private boolean accountNonLocked; 
    private Collection<? extends GrantedAuthority> authorities; 

    public LoggedUser() { 
    } 

    public LoggedUser(User user, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { 
    setUser(user); 
    this.enabled=enabled; 
    this.accountNonExpired=accountNonExpired; 
    this.credentialsNonExpired=credentialsNonExpired; 
    this.accountNonLocked=accountNonLocked; 
    this.authorities=authorities; 
    } 

    public void setUser(User user) { 
    this.user = user; 

    } 

    private User getUser() { 
    return this.user; 
    } 

    @Override 
    public Collection<? extends GrantedAuthority> getAuthorities() { 
    return this.authorities; 
    } 

    @Override 
    public String getPassword() { 
    return this.user.getPassword(); 
    } 

    @Override 
    public String getUsername() { 
    return this.user.getNickname(); 
    } 

    @Override 
    public boolean isAccountNonExpired() { 
    return this.accountNonExpired; 
    } 

    @Override 
    public boolean isAccountNonLocked() { 
    return this.accountNonLocked; 
    } 

    @Override 
    public boolean isCredentialsNonExpired() { 
    return this.credentialsNonExpired; 
    } 

    @Override 
    public boolean isEnabled() { 
    return this.enabled; 
    } 

    public String getEmail(){ 
    return this.user.getEmail(); 
    } 

    public int getId(){ 
    return this.user.getUserId(); 
    } 

    public Date getRegistrationDate(){ 
    return this.user.getRegistrationDate(); 
    } 
} 

feder security.xml

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns="http://www.springframework.org/schema/security" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security.xsd"> 

    <http auto-config="true" use-expressions="true"> 
    <intercept-url pattern="/sign/in" access="isAnonymous()" /> 
    <intercept-url pattern="/sign/up" access="isAnonymous()" /> 
    <intercept-url pattern="/secret/page" access="isAuthenticated()" /> 
    <intercept-url pattern="/sign/out" access="isAuthenticated()" /> 
    <intercept-url pattern="/user/myinfo" access="isAuthenticated()" /> 

    <form-login 
     login-page="/sign/in" 
     default-target-url="/secret/page" 
     authentication-failure-url="/sign/in?failed=1" 
     password-parameter="password" 
     username-parameter="email" 
    /> 
    <csrf disabled="true"/> 
    <logout 
     logout-url="/sign/out" 
    /> 
    </http> 

    <authentication-manager erase-credentials="false"> 
    <authentication-provider user-service-ref="customUserDetailsService"> 

    </authentication-provider> 
    </authentication-manager> 

    <beans:bean id="customUserDetailsService" class="milkiv.easyword.controller.sign.CustomUserDetailsService"/> 
</beans:beans> 

Und mein Test-Controller:

@RequestMapping(method = RequestMethod.POST, path = "/user/changepassword") 
     public String changePassword(@Valid @ModelAttribute("userPasswordChange") final UserPasswordChange userPasswordChange, BindingResult bindingResult, ModelMap model) { 
     if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails){ 
      //PRINTED 
      System.out.println("UserDetails +"); 
     } 
     if(SecurityContextHolder.getContext().getAuthentication().getPrincipal().getClass()==LoggedUser.class){ 
      //NOT PRINTED 
      System.out.println("LoggedUser +"); 
     } 
     try { 
      LoggedUser ud = (LoggedUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
     } catch (Exception ex) { 
      //PRINTED 
      System.out.println("LoggedUser -"); 
     } 
     //class org.springframework.security.core.userdetails.User 
System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal().getClass()); 
    return "user/myInfo"; 
     } 

EDIT: Stack Trace

testChangeUserPassword(milkiv.easyword.controller.sign.UserTest) Time elapsed: 0.896 sec <<< ERROR! 
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to milkiv.easyword.controller.sign.LoggedUser 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982) 
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) 
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) 
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) 
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) 
    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:169) 
    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.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158) 
    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.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.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.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.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) 
    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.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) 
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:156) 
    at milkiv.easyword.controller.sign.UserTest.testChangeUserPassword(UserTest.java:69) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:85) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:86) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:241) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:292) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:242) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:137) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189) 
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165) 
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85) 
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) 
Caused by: java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to milkiv.easyword.controller.sign.LoggedUser 
    at milkiv.easyword.controller.User.changePassword(User.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) 
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) 
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729) 
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) 
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
    ... 77 more 


Results : 

Tests in error: 
    testChangeUserPassword(milkiv.easyword.controller.sign.UserTest): Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to milkiv.easyword.controller.sign.LoggedUser 

EDIT: TEST

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath:resources/spring-context.xml", "classpath:resources/spring-security.xml"}) 
@WebAppConfiguration 
public class UserTest { 

    MockMvc mockMvc; 

    Storages storages; 

    @Autowired 
    private Filter springSecurityFilterChain; 

    @Autowired 
    WebApplicationContext wac; // cached 

    @Before 
    public void doBeforeTests() { 
    mockMvc = MockMvcBuilders 
     .webAppContextSetup(wac) 
     .addFilters(springSecurityFilterChain) 
     .build(); 
    ApplicationContext context = new ClassPathXmlApplicationContext("resources/spring-context.xml", "resources/spring-security.xml"); 
    storages = context.getBean(Storages.class); 
    } 

    @Test 
    public void testChangeUserPassword() throws Exception { 
    mockMvc.perform(post("/user/changepassword").with(user("[email protected]").password("test")) 
    ) 
     .andExpect(status().isOk()); 
    } 
} 
+1

Der Test wird Ihre benutzerdefinierten Details nicht verwenden, es wird einen regulären Spring Security-Benutzer erstellen. Daher der Classcast. Sie sollten eigentlich gegen die 'UserDetails'-Schnittstelle programmieren, nicht die konkrete Implementierung des Benutzers. Um es zu verwenden, erstellen Sie eine Instanz des 'LoggedUser' und übergeben Sie diese an die 'user' Methode. Das wird in diesem Blogpost https://spring.io/blog/2014/05/23/preview-spring-security-test-web-security#user-content-populating-a-test-user-with-annotations erklärt –

Antwort

1

Statt dessen:

user("[email protected]").password("test") 

Verwendung:

user(userDetails) 

wo userDetails eine Instanz Ihrer LoggedUser Klasse.

Verwandte Themen