如果一个系统分为前台用户和后台用户那么就不能使用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>
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 ; } }
<import resource="spring-etuser-security.xml"/>
<import resource="spring-disuser-security.xml"/>