2012-03-17 237 views
1

我已經編寫了自定義的UserDetailsS​​ervice來驗證數據庫中的用戶。第一次它工作正常,但當同一用戶嘗試登錄後第二次登錄後,它給出error.my應用程序基於 Spring 3.1與在Tomcat 7春季安全登錄/註銷問題

org.springframework.security.authentication.BadCredentialsException: Bad credentials 

這裏漂亮的面孔春季安全是我的配置細節的web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    version="2.5" metadata-complete="true"> 

<!-- The definition of the Root Spring Container shared by all Servlets 
    and Filters --> 
<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/spring/application-context.xml, 
     /WEB-INF/spring/application-context-security.xml 
    </param-value> 
</context-param> 

<context-param> 
    <param-name>primefaces.THEME</param-name> 
    <param-value>redmond</param-value> 
</context-param> 



<!-- Creates the Spring Container shared by all Servlets and Filters --> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<listener> 
    <listener-class> 
     org.springframework.web.context.request.RequestContextListener 
    </listener-class> 
</listener> 

<listener> 
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> 
</listener> 

<filter> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <filter-class> 
     org.springframework.web.filter.CharacterEncodingFilter 
    </filter-class> 
    <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<context-param> 
    <param-name>log4jConfigLocation</param-name> 
    <param-value>/WEB-INF/classes/log4j.properties</param-value> 
</context-param> 
<filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 
<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
    <dispatcher>FORWARD</dispatcher> 
    <dispatcher>REQUEST</dispatcher> 
</filter-mapping> 

<!-- Processes application requests --> 
<servlet> 
    <servlet-name>appServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value> 
      /WEB-INF/spring/application-context.xml, 
      /WEB-INF/spring/application-context-security.xml 
     </param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>appServlet</servlet-name> 
    <url-pattern>/jcsb</url-pattern> 
</servlet-mapping> 

    <!-- Pretty Face --> 
<filter> 
    <filter-name>Pretty Filter</filter-name> 
    <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>Pretty Filter</filter-name> 
    <url-pattern>/*</url-pattern> 
    <dispatcher>FORWARD</dispatcher> 
    <dispatcher>REQUEST</dispatcher> 
    <dispatcher>ERROR</dispatcher> 

</filter-mapping> 

<context-param> 
    <param-name>facelets.DEVELOPMENT</param-name> 
    <param-value>true</param-value> 
</context-param> 
<servlet> 
    <servlet-name>Faces Servlet</servlet-name> 
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>Faces Servlet</servlet-name> 
    <url-pattern>*.jsf</url-pattern> 
</servlet-mapping> 

<error-page> 
    <exception-type>org.springframework.security.access.AccessDeniedException</exception-type> 
    <location>/login.xhtml</location> 
</error-page> 

<session-config> 
    <session-timeout>10</session-timeout> 
</session-config> 

<error-page> 
    <exception-type>javax.faces.application.ViewExpiredException</exception-type> 
    <location>/index.html</location> 
</error-page> 

應用程序的context.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 

<!-- Root Context: defines shared resources visible to all other web components --> 
<context:component-scan base-package="com.swift.jcbs.web" /> 
<tx:annotation-driven /> 
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> 
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> 
    <property name="scopes"> 
     <map> 
      <entry key="view"> 
       <bean class="com.suraj.jcbs.web.spring.ViewScope"/> 
      </entry> 
     </map> 
    </property> 
</bean> 

應用程序上下文的security.xml

<?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:faces="http://www.springframework.org/schema/faces" 
    xmlns:int-security="http://www.springframework.org/schema/integration/security" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:sec="http://www.springframework.org/schema/security" 
    xsi:schemaLocation="http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-2.0.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd 
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-2.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

<sec:global-method-security 
    secured-annotations="enabled" jsr250-annotations="enabled" pre-post-annotations="enabled">  
</sec:global-method-security> 

    <!-- 
resource security 

Note: 
Access-denied-page is invoked when user is AUTHENTICATED but is not AUTHORIZED to access protected resources. 
When user is NOT AUTHENTICATED, he is moved into form-login instead of access-denied-page. 
--> 
<sec:http access-denied-page="/access_denied.xhtml" use-expressions="true" auto-config="true" > 
    <sec:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 
    <sec:form-login login-page="/login.jsf"/> 
    <sec:intercept-url pattern="/secured/**" access="isAuthenticated()"/> 
    <sec:intercept-url pattern="/WEB-INF/faces/**" access="isAuthenticated()"/> 

    <sec:logout logout-url="/logout" logout-success-url="/secured/home" delete-cookies="JSESSIONID" /> 
    <sec:session-management invalid-session-url="/secured/home"> 
     <sec:concurrency-control error-if-maximum-exceeded="true" max-sessions="6"/> 
    </sec:session-management> 
</sec:http> 


<!-- 
manager responsible for loading user account with assigned roles 
--> 
<sec:authentication-manager alias="authenticationManager"> 
    <sec:authentication-provider 
     user-service-ref="userVerificationService"/> 
</sec:authentication-manager> 

@Service 
    public class UserVerificationService implements UserDetailsService { 

private HashMap<String, org.springframework.security.core.userdetails.User> users = new HashMap<String, org.springframework.security.core.userdetails.User>(); 

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { 
    org.springframework.security.core.userdetails.User user = users.get(username); 

    if (user == null) { 
     throw new UsernameNotFoundException("UserAccount for name \"" 
       + username + "\" not found."); 
    } 

    return user; 
} 

@PostConstruct 
public void init() { 

    // sample roles  
    Collection<GrantedAuthority> adminAuthorities = new ArrayList<GrantedAuthority>(); 
    adminAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); 

    Collection<GrantedAuthority> userAuthorities = new ArrayList<GrantedAuthority>(); 
    adminAuthorities.add(new SimpleGrantedAuthority("ROLE_REGISTERED")); 


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

    // sample users with roles set 
    users.put("admin", new org.springframework.security.core.userdetails.User("admin", "admin", enabled, accountNonExpired, 
      credentialsNonExpired, accountNonLocked, adminAuthorities)); 

    users.put("user", new org.springframework.security.core.userdetails.User("user", "user", enabled, accountNonExpired, 
      credentialsNonExpired, accountNonLocked, userAuthorities)); 
} 



@Service 
public class AuthenticationServiceImpl implements AuthenticateService { 

@Resource(name = "authenticationManager") 
private AuthenticationManager authenticationManager; 

public boolean login(String username, String password) { 
    try { 
     System.out.println("inside login"); 
     System.out.println("AuthenticationServiceImpl user name " +username +" Pass = "+password); 
     Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
       username, password)); 
     SecurityContextHolder.getContext().setAuthentication(authenticate); 
     HttpUtils.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); 

     return true; 

    } catch (AuthenticationException e) { 
     e.printStackTrace(); 
    } 
    return false; 
} 

這裏是我的loginBean

public String process() { 

    System.out.println("user name " + username + " Pass = " + password); 
    if (authenticateService.login(username, password)) { 
     return "pretty:home"; 
    } else { 
     FacesUtils.addErrorMessage("Invalid UserName or Password"); 
     return null; 
    } 
} 

回答

5

從春天3.1開始,User Credentials are being erased這通常會導致一些問題。我通過關閉該功能解決了這個問題。

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager"> 
    <property name="eraseCredentialsAfterAuthentication" value="false"/> 
</bean> 

如果您正在使用的命名空間,你可以使用

<authentication-manager erase-credentials="false">