您的位置:首页 > 编程语言 > Java开发

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

2017-03-26 00:00 309 查看
如果一个系统分为前台用户和后台用户那么就不能使用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