Spring安全登录/注销问题

时间:2012-03-17 13:35:32

标签: spring-security

我已经编写了自定义UserDetailsS​​ervice来验证来自数据库的用户。第一次它工作正常但是当同一用户尝试登录后第二次登出时它给出了错误。我的应用程序基于 Spring 3.1,Spring安全与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;
    }
}

1 个答案:

答案 0 :(得分:5)

从Spring 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">