Spring Security UserDetailsS​​ervice未验证密码

时间:2011-03-30 22:12:46

标签: spring spring-security

我正在实现spring security 3.0.5,并在我的基于表单的登录中扩展了Spring UserDetailsS​​ervice。目前我的登录表单只验证用户名而不是密码。 spring security在哪里验证发布到/ j_spring_security_check的密码?

安全配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
    xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:annotation-config />
    <context:component-scan base-package="dc" />
    <global-method-security />
    <http access-denied-page="/auth/denied.html">
         <intercept-url filters="none" pattern="/javax.faces.resource/**" />
         <intercept-url filters="none" pattern="/services/rest-api/1.0/**" />
         <intercept-url filters="none" pattern="/preregistered/*"/>
         <intercept-url
            pattern="/**/*.xhtml"
            access="ROLE_NONE_GETS_ACCESS" />
        <intercept-url
            pattern="/auth/**"
            access="ROLE_ANONYMOUS,ROLE_USER" />
         <intercept-url
            pattern="/auth/*"
            access="ROLE_ANONYMOUS" />
         <intercept-url
            pattern="/registered/*"
            access="ROLE_USER" />
          <intercept-url
            pattern="/*"
           access="ROLE_ANONYMOUS" />
        <form-login
            login-processing-url="/j_spring_security_check.html"
            login-page="/auth/login.html"
            default-target-url="/home.html"
            authentication-failure-url="/login.html" />
         <logout invalidate-session="true" 
              logout-url="logout.html" 
              success-handler-ref="SuccessHandler"/>
        <anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
        <remember-me user-service-ref="userManager" key="dfdfdfdff"/>
        <custom-filter after="FORM_LOGIN_FILTER" ref="xmlAuthenticationFilter"/>
    </http>
    <!-- Configure the authentication provider -->
    <authentication-manager alias="am">
        <authentication-provider user-service-ref="userManager">
                <password-encoder ref="passwordEncoder" />
        </authentication-provider>
        <authentication-provider ref="xmlAuthenticationProvider" />
    </authentication-manager>
</beans:beans>

豆:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.dc"/>
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    <bean id="springContextHolder" class="SpringContextHolder" factory-method="getInstance" />
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="MYSQL" />
                <property name="showSql" value="true" />
            </bean>
        </property>
    </bean>
     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/webapp" />
        <property name="username" value="userid" />
        <property name="password" value="password" />
    </bean>       
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="localhost"/>
        <property name="port" value="25"/>
    </bean>
    <bean id="utilities" class="UtilitiesImpl"/>
    <bean id="xmlAuthenticationFilter" class="com.dc.api.service.impl.XMLAuthenticationFilter">
        <property name="authenticationManager" ref="am" />
        <property name="utilities" ref="utilities"/>
    </bean>
    <bean id="xmlAuthenticationProvider" class="com.dc.api.service.impl.XMLAuthenticationProvider">
        <property name="userManager" ref="userManager"/>
    </bean>
    <bean id="DCLogoutSuccessHandler" class="LogoutSuccessHandler"/>
 </beans>

UserDetails实施:

import javax.inject.Inject;

import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.dc.api.dao.AuthorityDAO;
import com.dc.api.dao.UserDAO;
import com.dc.api.exception.ApiDataException;
import com.dc.api.exception.EmailNotFoundException;
import com.dc.api.helper.MailContentHelper;
import com.dc.api.model.Users;
import com.dc.api.model.vo.APIResponse;
import com.dc.api.service.UserManager;
import com.dc.api.service.Utilities;

@Service("userManager")
public class UserManagerImpl extends UserDetailsService {
    @Inject
    UserDAO userDAO;
    @Inject
    AuthorityDAO authorityDAO;
    @Inject
    PasswordEncoder passwordEncoder;
    @Inject
    Utilities utilities;

    private void encodePassword(Users user) {
        if (user.getPassword() == null && user.getRawPassword() != null) {
            user.setPassword(passwordEncoder.encodePassword(user.getRawPassword(), null));
            user.setRawPassword(null);
        }
    }

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        Users user = null;
        try {
            user = userDAO.findByUsername(username);
            if (user != null) {

            }
        } catch (DataAccessException ex) {
            throw new UsernameNotFoundException("Invalid login", ex);
        }
        if (user == null) {
            throw new UsernameNotFoundException("User not found.");
        }
        return user;
    }

    public Users getUser(String username) {
        try {
            return userDAO.findByUsername(username);
        } catch (DataAccessException ex) {
            // ignore
            log.warn("Duplicate username: " + username);
        }
        return null;
    }

    public boolean isUsernameTaken(String username) {
        try {
            if (userDAO.findByUsername(username) == null) {
                return false;
            } else {
                return true;
            }
        } catch (DataAccessException ex) {
            // ignore
            log.warn("Duplicate username: " + username);
        }
        return true;
    }

    public boolean isLoginValid(String username, String password) throws ApiDataException {
        Users user = null;
        try {
            user = userDAO.findByUsername(username);
        } catch (DataAccessException ex) {
            throw new ApiDataException("Data Access Exception while verifying login");
        }
        if (user == null) {
            return false;
        }
        if (passwordEncoder.isPasswordValid(user.getPassword(), password, null)) {
            return true;
        }
        return false;
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void saveUser(Users user) {
        encodePassword(user);
        userDAO.save(user);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void updateUser(Users user) {
        encodePassword(user);
        userDAO.update(user);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void resetPassword(String username, MailContentHelper mailContentHelper) {
        String newPassword = utilities.generateSecret(8);
        this.changePassword(username, newPassword, mailContentHelper);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void changePassword(String username, String password, MailContentHelper mailContentHelper) {
        Users user = userDAO.findByUsername(username);
        user.setPassword(null);
        user.setRawPassword(password);
        encodePassword(user);
        userDAO.update(user);
        String firstName = user.getFirstName();
        firstName = (firstName == null) ? user.getUsername() : firstName;
        //SimpleMailMessage message = mailContentHelper.retrieveContent(new Object[]{firstName, password, user.getEmail()});
        //utilities.sendMail(message);
    }
}

的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">
  <context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/facelet/dc.taglib.xml</param-value>
  </context-param>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        WEB-INF/dc-context-api.xml
        WEB-INF/dc-context-security.xml
    </param-value>
  </context-param>
  <context-param>
    <param-name>resteasy.resource.method-interceptors</param-name>
    <param-value>org.jboss.resteasy.core.ResourceMethodSecurityInterceptor</param-value>
  </context-param>
  <context-param>
    <param-name>resteasy.resources</param-name>
    <param-value>
         com.dc.web.actions.GlobalWebService</param-value>
  </context-param>
  <context-param>
    <param-name>resteasy.servlet.mapping.prefix</param-name>
    <param-value>/services/rest-api</param-value>
  </context-param>
  <context-param>
    <param-name>resteasy.media.type.mappings</param-name>
    <param-value>json : application/json, xml : application/xml</param-value>
  </context-param>
  <context-param>
    <param-name>resteasy.resources</param-name>
    <param-value>
            com.WebService
        </param-value>
  </context-param>
  <context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>none</param-value>
  </context-param>
  <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>
     <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>1000</param-value>
    </context-param>
    <context-param> 
        <param-name>primefaces.PRIVATE_CAPTCHA_KEY</param-name> 
        <param-value>6LeL-MISAAAAAG6k07ch22oy-mxXBUi1MXKmrWiD</param-value>
    </context-param>
    <context-param> 
        <param-name>primefaces.PUBLIC_CAPTCHA_KEY</param-name> 
        <param-value>6LeL-MISAAAAAPTK5lYI9tK0SWWY2BqC2Hun7sH3</param-value>
    </context-param>
  <filter> 
    <filter-name>PrimeFaces FileUpload Filter</filter-name> 
        <filter-class>org.primefaces.webapp.filter.FileUploadFilter </filter-class>
        <init-param> 
            <param-name>thresholdSize</param-name> <param-value>51200</param-value>
        </init-param> 
        <init-param>
            <param-name>uploadDirectory</param-name>
            <param-value>url/upload</param-value> 
        </init-param>
    </filter>
  <filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
  </filter-mapping>
  <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>*.html</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>*.xhtml</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/dc_security_check</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <listener>
    <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
  </listener>
  <listener>
    <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
  <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
  <servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
  </servlet>
  <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>Resteasy</servlet-name>
    <url-pattern>api/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  <login-config>
    <auth-method>BASIC</auth-method>
  </login-config>
</web-app>

1 个答案:

答案 0 :(得分:3)

它会将您提交的密码与UserDetails返回的UserDetailsService对象返回的密码进行比较。如果您需要更多帮助,请发布您的配置和UserDetailsService

编辑:感谢您的信息。它完全符合您的猜测。 ProviderManager(默认情况下使用)在其JavaDoc中具有以下内容:

  

如果后续提供商成功   验证请求,更早   身份验证例外是   无视和成功   将使用身份验证。

所以你的问题是后一个提供者“推翻”第一个决定。