spring security 自定义登录:
1、自定义表结构
T_USER:(用户表)
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar,
`password` varchar
T_ROLE:(角色表)
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`role` varchar--角色名(spring security定义角色名以ROLE_开头)
T_USER_ROLE:(用户角色关联表)
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(11),
`role_id` bigint(11)
2、需要的jar包:
spring-security-acl-3.1.0.RC2.jar
spring-security-aspects-3.1.0.RC2.jar
spring-security-cas-3.1.0.RC2.jar
spring-security-config-3.1.0.RC2.jar
spring-security-core-3.1.0.RC2.jar
spring-security-ldap-3.1.0.RC2.jar
spring-security-openid-3.1.0.RC2.jar
spring-security-taglibs-3.1.0.RC2.jar
spring-security-web-3.1.0.RC2.jar
3、登录页面login.jsp
<form id="loginForm" action="<c:url value='/j_spring_security_check'/>" method="post"> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <th>用户名:</th> <td><input type="text" name="j_username" id="username" class="input" value="<c:if test='${not empty param.login_error}' > <c:out value='${SPRING_SECURITY_LAST_USERNAME}'/> </c:if>" /> </td> <td rowspan="3"><a onclick="javascript:login();"><img src="../img/home/login_btn.gif" width="111" height="99" /> </a></td> </tr> <tr> <th>密 码:</th> <td><input type="password" name="j_password" id="password" class="input" /></td> </tr> <tr> <th>验证码:</th> <td><input type="text" maxlength="4" name="code" id="code" class="input" style="width: 80px;" onkeypress="javascript:pressKey(event);" /> <img id="validateCode" src="validate.code" width="75" height="33" /> <a onclick="javascript:reload();"><img src="../img/home/refresh.gif" width="22" height="22" /> </a> </td> </tr> </table> </form> <c:if test="${not empty param.error}"> <font color="red"> 登录失败<br /> <br /> 原因: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" /></font> </c:if>
4、application-security.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:beans="http://www.springframework.org/schema/beans" 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/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <http> <!-- 不拦截 --> <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" /> <intercept-url pattern="/list/**" access="ROLE_ADMIN,ROLE_MANAGER,ROLE_USER" /> <intercept-url pattern="/delete/**" access="ROLE_ADMIN" /> <!-- 设置登录过滤器 --> <custom-filter before="FORM_LOGIN_FILTER" ref="validateCodeAuthenticationFilter" /> <!-- 登录表单设置 --> <form-login login-page="/home/login" default-target-url="/home/loginSuccess.action"(登录成功的url) authentication-failure-url="/home/login.action?error=true"(登录失败的url) /> <!-- 登出操作后跳转到该页面 --> <!-- <logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID" /> <remember-me /> --> <!-- SESSION超时后跳转到该页面 --> <!-- <session-management invalid-session-url="/timeout.jsp"> </session-management> --> </http> <authentication-manager alias="authenticationManager"> <authentication-provider> <!-- 直接使用SQL语句查询登录帐号对应权限, users-by-username-query:查询登录用户是否存在 authorities-by-username-query:查询登录用户权限(登录用户可以不属于任何组,从t_user_role表中获取权限) group-authorities-by-username-query:查询登录用户所在组的权限 --> <jdbc-user-service data-source-ref="webDataSource" users-by-username-query="SELECT t_user.name AS username,t_user.password as password,'true' AS enabled FROM t_user WHERE t_user.name = ?" authorities-by-username-query="SELECT name AS username,role as authorities FROM T_USER LEFT OUTER JOIN t_role AS userrole ON(t_user.id = userrole.user_id) LEFT OUTER JOIN t_role AS role ON (userrole.role_id = role.id) WHERE t_user.name = ?" /> </authentication-provider> </authentication-manager> <!-- 验证码过滤器 --> <beans:bean id="validateCodeAuthenticationFilter" class="**.**.security.ValidateCodeUsernamePasswordAuthenticationFilter"> <beans:property name="authenticationSuccessHandler" ref="loginLogAuthenticationSuccessHandler"></beans:property> <beans:property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler"></beans:property> <beans:property name="authenticationManager" ref="authenticationManager"></beans:property> </beans:bean> <!-- 登录成功 --> <beans:bean id="loginLogAuthenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/home/loginSuccess.action"></beans:property> </beans:bean> <!-- 登录失败 --> <beans:bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/home/login.action?error=true"></beans:property> </beans:bean> </beans:beans>
5、验证码验证
package cn.com.trade.security; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; 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.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.TextEscapeUtils; import cn.com.fxark.util.md5.MD5; import cn.com.trade.domain.adminuser.AdminUser; import cn.com.trade.global.GlobalParameter; import cn.com.trade.service.ServiceManager; /** * 带验证码校验功能的用户名、密码认证过滤器 * * 支持不输入验证码;支持验证码忽略大小写。 * * @author Long * */ public class ValidateCodeUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private boolean postOnly = true; private boolean allowEmptyValidateCode = false; private String sessionvalidateCodeField = DEFAULT_SESSION_VALIDATE_CODE_FIELD; private String validateCodeParameter = DEFAULT_VALIDATE_CODE_PARAMETER; public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME"; // session中保存的验证码 public static final String DEFAULT_SESSION_VALIDATE_CODE_FIELD = "rand"; // 输入的验证码 public static final String DEFAULT_VALIDATE_CODE_PARAMETER = "code"; @Override 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); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // Place the last username attempted into HttpSession for views HttpSession session = request.getSession(false); if (session != null || getAllowSessionCreation()) { request.getSession().setAttribute( SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username)); } // Allow subclasses to set the "details" property setDetails(request, authRequest); // check validate code if (!isAllowEmptyValidateCode()) checkValidateCode(request); // 根据用户和密码查询 AdminUser adminUser = ServiceManager.getInstance() .getAdminUserService() .login(username, MD5.getMD5ofStr(password)); session.setAttribute(GlobalParameter.HT_ADMIN_LOGIN_USER_SESSION_NAME, adminUser); return this.getAuthenticationManager().authenticate(authRequest); } /** * * <li>比较session中的验证码和用户输入的验证码是否相等</li> * */ protected void checkValidateCode(HttpServletRequest request) { String sessionValidateCode = obtainSessionValidateCode(request); String validateCodeParameter = obtainValidateCodeParameter(request); if (StringUtils.isEmpty(validateCodeParameter) || !sessionValidateCode.equalsIgnoreCase(validateCodeParameter)) { throw new AuthenticationServiceException("验证码错误!"); } } private String obtainValidateCodeParameter(HttpServletRequest request) { return request.getParameter(validateCodeParameter); } protected String obtainSessionValidateCode(HttpServletRequest request) { Object obj = request.getSession() .getAttribute(sessionvalidateCodeField); return null == obj ? "" : obj.toString(); } public boolean isPostOnly() { return postOnly; } @Override public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public String getValidateCodeName() { return sessionvalidateCodeField; } public void setValidateCodeName(String validateCodeName) { this.sessionvalidateCodeField = validateCodeName; } public boolean isAllowEmptyValidateCode() { return allowEmptyValidateCode; } public void setAllowEmptyValidateCode(boolean allowEmptyValidateCode) { this.allowEmptyValidateCode = allowEmptyValidateCode; } }