目录
SpringSecurity3.X--一个简单实现
SpringSecurity3.X--前台与后台登录认证
SpringSecurity3.X--remember-me
SpringSecurity3.X--验证码
一般来说,登录时都会要求用户输入验证码,以防止恶意登录。
可是,SpringSecurity并没有为我们提供这样的功能,所以就需要我们自己来解决了。
那么该如何解决呢,其实也挺简单的,
核对验证码信息,当然是在登录时处理的,所以,使用filter是最佳选择。
既然确定了方向,那么久该考虑如何增加这个filter了,其实可以有两种方案:
1.继承UsernamePasswordAuthenticationFilter ,在里面增加验证码验证规则即可;
2.自己定义一个filter,专门处理验证码验证;
笔者这里推荐使用第二种方案,因为第一种我们需要显示声明login-filter,所以需要修改SpringSecurity的配置文件,而方案2根本不需要修改,只需要向一般的filter一样,在web.xml中增加配置即可,唯一需要注意的是,mapping一定要与触发login-filter的url一致,如下所示:
<filter> <filter-name>imageFilter</filter-name> <filter-class>com.piaoyi.common.filter.ImageFilter</filter-class> </filter> <filter-mapping> <filter-name>imageFilter</filter-name> <url-pattern>/j_spring_security_check</url-pattern> </filter-mapping>
另外需要注意的是,该filter的mapping一定要声明在springSecurityFilterChain的mapping之前,这样可以保证请求先被imageFilter处理。
设计思路就是这样的,这里给出一个简单的实现。
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/jsp/common/includes.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆</title>
</head>
<body>
<center>
<div class="error">
${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message }</div>
<form name='f' id='f'
action='<%=request.getContextPath()%>/j_spring_security_check'
method='POST'>
<table style="width: 50%">
<tr>
<td style="text-align: right; width: 35%">用户名称 :</td>
<td style="text-align: left"><input type='text'
name='j_username' value=''></td>
</tr>
<tr>
<td style="text-align: right">密码 :</td>
<td style="text-align: left"><input type='password'
name='j_password' /></td>
</tr>
<tr>
<td style="text-align: right"><label for="j_captcha"> 验证码: </label></td>
<td>
<input type='text' name='j_captcha' class="required"
size='5' />
<img id="imageF" src="<c:url value="/resource/image.jsp"/>" />
<a href="#" id="flashImage">看不清楚换一张</a>
</td>
</tr>
<tr>
<td align="right"><input id="_spring_security_remember_me"
name="_spring_security_remember_me" type="checkbox" value="true" />
</td>
<td><label for="_spring_security_remember_me">Remember Me?</label>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center"><input
type="submit" name="submit" value="登录" /></td>
</tr>
</table>
</form>
</center>
<script type="text/javascript">
document.f.j_username.focus();
if ('${message}' == 1) {
alert("用户名或密码错误");
}
jQuery(function($){
$("#flashImage").click(function(){
$('#imageF').hide().attr('src','<c:url value="/resource/image.jsp"/>'+ '?'+ Math.floor(Math.random() * 100)).fadeIn();
});
});
</script>
</body>
</html>
ImageFilter.java
package com.piaoyi.common.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ImageFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
String yanzhengm = request.getParameter("j_captcha");
String sessionyanz = (String)request.getSession(true).getAttribute("yzkeyword");
if(yanzhengm.equals(sessionyanz)){
arg2.doFilter(request, response);
}else{
response.sendRedirect("/login.do");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
image.jsp
<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" pageEncoding="UTF-8"%>
<%!
Color getRandColor(int fc,int bc){//随机获得颜色,RGB格式
Random random = new Random();
if(fc>255) fc=255;
if(bc>255) bc=255;
int r=fc+random.nextInt(bc-fc);
int g=fc+random.nextInt(bc-fc);
int b=fc+random.nextInt(bc-fc);
return new Color(r,g,b);
}
%>
<%
//清除缓存,每次访问该页面时都从服务器端读取
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
// 定义显示图片的宽度和高度
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 画图画板
Graphics g = image.getGraphics();
//定义一个随机数
Random random = new Random();
// 设置画板背景颜色
g.setColor(getRandColor(200,250));
//设置画板的填充范围
g.fillRect(0, 0, width, height);
//设置字体
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
// 设置线条颜色并画线,155条
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x,y,x+xl,y+yl);
}
// 显示数字,4位长度
String sRand="";
for (int i=0;i<4;i++){
String rand=String.valueOf(random.nextInt(10));
sRand+=rand;
// 设置每个数字的颜色
g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
//在画板上写数字,起始位置
g.drawString(rand,13*i+6,16);
}
// 保存进session
session.setAttribute("yzkeyword",sRand);
//System.out.println("yzm:"+sRand);
// 显示图片
g.dispose();
%>
<%
//转换成一张图片,格式为JPEG
ImageIO.write(image, "JPEG", response.getOutputStream());
out.clear();//清空缓存的内容。
pageContext.pushBody();
%>
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tool="http://www.springframework.org/schema/tool" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd" default-lazy-init="true"> <http security="none" pattern="/index.do" /> <http auto-config='true' access-decision-manager-ref="accessDecisionManager" access-denied-page="/index.do"> <intercept-url pattern="/demo.do*" access="IS_AUTHENTICATED_REMEMBERED" /> <intercept-url pattern="/**/*.do*" access="HODLE" /> <logout logout-url="/logout.do" invalidate-session="true" logout-success-url="/logout.jsp" /> <form-login login-page="/index.do" default-target-url="/frame.do" always-use-default-target="true" authentication-failure-url="/index.do?login_error=1" /> <session-management> <concurrency-control max-sessions="1" expired-url="/timeout.jsp"/> </session-management> <remember-me key="jbcpPetStore" /> </http> <!-- Automatically receives AuthenticationEvent messages --> <beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener" /> <authentication-manager erase-credentials="false"> <authentication-provider user-service-ref="userService"> <password-encoder hash="md5" /> </authentication-provider> </authentication-manager> <beans:bean id="userService" class="com.piaoyi.common.security.UserService" /> <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <beans:property name="decisionVoters"> <beans:list> <beans:bean class="org.springframework.security.access.vote.RoleVoter" /> <beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> <beans:bean class="com.piaoyi.common.security.DynamicRoleVoter" /> </beans:list> </beans:property> </beans:bean> </beans:beans>
效果图如下:
另外,从网上也看到了类似的解决方案:
springsecurity3和JCaptcha的整合
里面使用到了jcaptcha的jar包,我整合后发现也很好用,附件中给出jar包。