spring-security 多类型用户登录+登录多参数验证

如果一个系统分为前台用户和后台用户那么就不能使用spring-security的默认配置了。 需要自己来分开配置两种用户的登录方式。

首先创建spring-disuser-security.xml 与 spring-etuser-security.xml 两个配置文件,分别来配置两种用户登录的权限与验证方式

spring-disuser-security.xml的内容如下

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:security="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/aop 
		http://www.springframework.org/schema/aop/spring-aop-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/context
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/security   
        http://www.springframework.org/schema/security/spring-security-3.1.xsd">
        
        <!-- 使用自定义Filter时需要将http节点的auto-config="true"属性删除,并且要通过entry-point-ref指定一个入口  -->
        <security:http use-expressions="true" access-denied-page="/powermiss.jsp" 
     	  	authentication-manager-ref="disuserAuthManager" name="disuserSecurity" 
     	  	entry-point-ref="authenticationEntryPoint">
        	<security:intercept-url pattern="/disuserlogin.jsp"  access="permitAll"/>
        	<!-- 配置自定义的Filter,并且将其放在FORM_LOGIN_FILTER节点,就会替换掉原来的FORM_LOGIN_FILTER节点  -->
        	<security:custom-filter ref="loginProcessFilter" position="FORM_LOGIN_FILTER"/>  
        </security:http>  
           
	    <security:authentication-manager id="disuserAuthManager" >  
	        <security:authentication-provider user-service-ref="DisuserserDetailService" />
	    </security:authentication-manager>   
		
		<!-- 登录处理Filter  -->
		<bean id="loginProcessFilter" class="com.tuanfang.service.DisUsernamePasswordAuthenticationFilter">
			<property name="loginid" value="loginid" />
			<property name="yzm" value="yzm" />
			<property name="usernameParameter" value="username" />  
			<property name="passwordParameter" value="password" />
			<property name="filterProcessesUrl" value="/disuserlogin.htm" />
			<property name="authenticationManager" ref="disuserAuthManager" />
			<property name="authenticationSuccessHandler" ref="successHandler" />
			<property name="authenticationFailureHandler" ref="failureHandler" />
		</bean>		
		
		<!-- 登录成功处理 -->
		<bean id="successHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
			<property name="defaultTargetUrl" value="/index.jsp" />
			<property name="alwaysUseDefaultTargetUrl" value="true" />
		</bean>
		
		<!-- 登录失败处理 -->
		<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
		 	 <property name="defaultFailureUrl" value="/disuserlogin.jsp?error=true" />
		</bean>
		
	  <!-- 登录入口 --> 
	   <bean id="authenticationEntryPoint"  
	        class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
	        <property name="loginFormUrl" value="/disuserlogin.jsp" />  
       </bean>  
</beans>


接下来编写DisUsernamePasswordAuthenticationFilter.java文件,处理用户登录。

spring-security默认的处理登录的类是org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter,可以将其中的代码复制到自己写的DisUsernamePasswordAuthenticationFilter.java文件中。

然后在进行自己的修改,达到验证验证码,与公司登录id的验证。

/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tuanfang.service;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;


/**
 * Processes an authentication form submission. Called {@code AuthenticationProcessingFilter} prior to Spring Security
 * 3.0.
 * <p>
 * Login forms must present two parameters to this filter: a username and
 * password. The default parameter names to use are contained in the
 * static fields {@link #SPRING_SECURITY_FORM_USERNAME_KEY} and {@link #SPRING_SECURITY_FORM_PASSWORD_KEY}.
 * The parameter names can also be changed by setting the {@code usernameParameter} and {@code passwordParameter}
 * properties.
 * <p>
 * This filter by default responds to the URL {@code /j_spring_security_check}.
 *
 * @author Ben Alex
 * @author Colin Sampaleanu
 * @author Luke Taylor
 * @since 3.0
 */
public class DisUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    //~ Static fields/initializers =====================================================================================

    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    public static final String SPRING_SECURITY_FORM_YZM_KEY = "yzm";
    public static final String SPRING_SECURITY_FORM_LOGINID_KEY = "loginid";
    public static final String USERNAME_LOGINID_SPLIT = "/";
    /**
     * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler}
     */
    @Deprecated
    public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";

    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
    private String yzm = SPRING_SECURITY_FORM_YZM_KEY;
    private String loginid = SPRING_SECURITY_FORM_LOGINID_KEY;
    private boolean postOnly = true;

    //~ Constructors ===================================================================================================

    public DisUsernamePasswordAuthenticationFilter() {
        super("/j_spring_security_check");
    }

    //~ Methods ========================================================================================================

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        String loginid = obtainLoginid(request);
        String yzm = obtainYzm(request);
        
        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }
        
        if (loginid == null) {
        	loginid = "";
        }
        
        if (yzm == null) {
        	yzm = "";
        }

        username = username.trim();
        password = password.trim();
        loginid = loginid.trim();
        yzm = yzm.trim();
        
        username = loginid + USERNAME_LOGINID_SPLIT + username ;   //将公司登录id与登录用户名使用 / 连接起来

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * Enables subclasses to override the composition of the password, such as by including additional values
     * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the
     * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The
     * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p>
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the password that will be presented in the <code>Authentication</code> request token to the
     *         <code>AuthenticationManager</code>
     */
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }
    
    //获取验证码
    protected String obtainYzm(HttpServletRequest request){
    	   return request.getParameter(yzm);
    }
    
    //获取公司id
    protected String obtainLoginid(HttpServletRequest request){
    	   return request.getParameter(loginid);
    }
    
    
    
    /**
     * Enables subclasses to override the composition of the username, such as by including additional values
     * and a separator.
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the username that will be presented in the <code>Authentication</code> request token to the
     *         <code>AuthenticationManager</code>
     */
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    /**
     * Provided so that subclasses may configure what is put into the authentication request's details
     * property.
     *
     * @param request that an authentication request is being created for
     * @param authRequest the authentication request object that should have its details set
     */
    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    /**
     * Sets the parameter name which will be used to obtain the username from the login request.
     *
     * @param usernameParameter the parameter name. Defaults to "j_username".
     */
    public void setUsernameParameter(String usernameParameter) {
        Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
        this.usernameParameter = usernameParameter;
    }

    /**
     * Sets the parameter name which will be used to obtain the password from the login request..
     *
     * @param passwordParameter the parameter name. Defaults to "j_password".
     */
    public void setPasswordParameter(String passwordParameter) {
        Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
        this.passwordParameter = passwordParameter;
    }

    /**
     * Defines whether only HTTP POST requests will be allowed by this filter.
     * If set to true, and an authentication request is received which is not a POST request, an exception will
     * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method
     * will be called as if handling a failed authentication.
     * <p>
     * Defaults to <tt>true</tt> but may be overridden by subclasses.
     */
    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

    public final String getUsernameParameter() {
        return usernameParameter;
    }

    public final String getPasswordParameter() {
        return passwordParameter;
    }

	public String getYzm() {
		return yzm;
	}

	public void setYzm(String yzm) {
		this.yzm = yzm;
	}

	public String getLoginid() {
		return loginid;
	}

	public void setLoginid(String loginid) {
		this.loginid = loginid;
	}
}


接下来编写提供Disuser的UserDetailsService类

package com.tuanfang.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;

import com.tuanfang.dao.impl.DisuserDaoImpl;
import com.tuanfang.dao.impl.SysPowrDaoImpl;
import com.tuanfang.pojo.Disuser;
import com.tuanfang.pojo.SysPower;

@Repository("DisuserserDetailService")  
public class DisuserserDetailService implements UserDetailsService{
	
	@Resource(name="DisuserDaoImpl")
	private DisuserDaoImpl disuserDao ;
	
	@Resource(name="SysPowrDaoImpl")
	private SysPowrDaoImpl sysPowrDao ;

	@Override
	public UserDetails loadUserByUsername(String usernameAndloginId)
			throws UsernameNotFoundException {
		//将公司登录id与登录用户名使用/分开
		String args[]  = usernameAndloginId.split(DisUsernamePasswordAuthenticationFilter.USERNAME_LOGINID_SPLIT);
		String loginid = args[0];
		String username = args[1];
		Disuser disuser =  disuserDao.findByLoginIdAndUserName(loginid , username);
		UserDetails userDetail = null ;
		if(disuser != null){
			userDetail = new User(username, disuser.getPassword(),disuser.getStatus() ==Disuser.ENABLE ,
					true, true, true, obtainUserPowers(disuser.getId()));
		}
		return userDetail;
	}
	
	public Collection<GrantedAuthority> obtainUserPowers(BigInteger userId){
		Collection<GrantedAuthority> gas = new ArrayList<GrantedAuthority>();
		List<SysPower> powers = sysPowrDao.findDisuserPowers(userId);
		if(powers != null && powers.size() > 0){
			for (SysPower sysPower : powers) {  
				gas.add(new SimpleGrantedAuthority(sysPower.getCode()));   
			}
		}
		gas.add(new SimpleGrantedAuthority("HAVE_LOGIN"));	//登录    
		return gas ;
	}

}


登录页面disuserlogin.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%  
String path = request.getContextPath();  
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
%>  
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>DisuserLogin</title>
</head>
<body>
     
	<form action="<%=basePath %>disuserlogin.htm" method="post">      
        <p> 
            <label for="username">Username</label> <input id="username"    
                name="username" type="text" />    
        </p>    
    
        <p>    
            <label for="password">password</label> <input id="password"    
                name="password" type="password" />            
        </p>    
          
    
        <p>    
            <label for="loginid">LoginId</label> <input id="loginid"    
                name="loginid" type="text" />            
        </p>    
          
    
        <p>    
            <label for="yzm">验证码</label> <input id="yzm"    
                name="yzm" type="text" />            
        </p>    
          
        <input type="submit" value="Login" /> 
    </form>    
	
	  
</body>
</html>




这样就配置好了Disuser的login



接下来配置EtdsUser的login。只需要username与password

spring-etuser-security.xml文件内容如下(使用spring-security默认的方式配置):

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:security="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/aop 
		http://www.springframework.org/schema/aop/spring-aop-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/context
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/security   
        http://www.springframework.org/schema/security/spring-security-3.1.xsd">
        
        <security:http auto-config="true" pattern="/admin/**" use-expressions="true" access-denied-page="/powermiss.jsp" 
        authentication-manager-ref="etuserAuthManager" name="etuserSecurity">
        	<security:intercept-url pattern="/admin/etuserlogin.jsp"  access="permitAll"/>
        	<security:form-login login-processing-url="/admin/j_spring_security_check" authentication-failure-url="/admin/etuserlogin.jsp?error=true"  login-page="/admin/etuserlogin.jsp" 
        		 default-target-url="/index.jsp" />
        </security:http>  
           
        
	    <security:authentication-manager id="etuserAuthManager" >  
	        <security:authentication-provider user-service-ref="EtuserDetailService"/>
	    </security:authentication-manager>   
		
	
</beans>

Etdsuser的UserDetailsService类如下:

package com.tuanfang.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;

import com.tuanfang.dao.impl.EtdsuserDaoImpl;
import com.tuanfang.dao.impl.SysPowrDaoImpl;
import com.tuanfang.pojo.EtdsUser;
import com.tuanfang.pojo.SysPower;

@Repository("EtuserDetailService")  
public class EtuserDetailService implements UserDetailsService{
	
	@Resource(name="EtdsuserDaoImpl")
	private EtdsuserDaoImpl etdsuserDao ;
	
	@Resource(name="SysPowrDaoImpl")
	private SysPowrDaoImpl sysPowrDao ;

	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		EtdsUser etuser =  etdsuserDao.findUserByLoginName(username);
		UserDetails userDetail = null ;
		if(etuser != null){
			userDetail = new User(username, etuser.getPassword(),etuser.getStatus() ==EtdsUser.ENABLE ,
					true, true, true, obtainUserPowers(etuser.getId()));  
		}
		return userDetail;
	}
	
	public Collection<GrantedAuthority> obtainUserPowers(BigInteger userId){
		Collection<GrantedAuthority> gas = new ArrayList<GrantedAuthority>();
		List<SysPower> powers = sysPowrDao.findEtuserPowers(userId);
		if(powers != null && powers.size() > 0){
			for (SysPower sysPower : powers) {  
				gas.add(new SimpleGrantedAuthority(sysPower.getCode()));   
			}
		}
		gas.add(new SimpleGrantedAuthority("HAVE_LOGIN"));	//登录   
		return gas ;
	}

}

然后在applicationContext.xml中导入spring-disuser-security.xml与spring-etuser-security.xml


<import resource="spring-etuser-security.xml"/>
<import resource="spring-disuser-security.xml"/>




你可能感兴趣的:(spring-security 多类型用户登录+登录多参数验证)