SpringSecurity3.X--验证码
- 博客分类:
- Spring
- SpringSecurity
springspringsecurity
目录
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一致,如下所示:
1. <filter>
2. <filter-name>imageFilter</filter-name>
3. <filter-class>com.piaoyi.common.filter.ImageFilter</filter-class>
4.
5. </filter>
6. <filter-mapping>
7. <filter-name>imageFilter</filter-name>
8. <url-pattern>/j_spring_security_check</url-pattern>
9. </filter-mapping>
<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>
<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>
<%@ 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>
1. <%@ page language="java" contentType="text/html; charset=UTF-8"
2. pageEncoding="UTF-8"%>
3. <%@ include file="/WEB-INF/views/jsp/common/includes.jsp"%>
4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
5. <html>
6. <head>
7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
8. <title>登陆</title>
9. </head>
10. <body>
11.
12. <center>
13. <div class="error">
14. ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message }</div>
15. <form name='f' id='f'
16. action='<%=request.getContextPath()%>/j_spring_security_check'
17. method='POST'>
18. <table style="width: 50%">
19. <tr>
20. <td style="text-align: right; width: 35%">用户名称 :</td>
21. <td style="text-align: left"><input type='text'
22. name='j_username' value=''></td>
23. </tr>
24. <tr>
25. <td style="text-align: right">密码 :</td>
26. <td style="text-align: left"><input type='password'
27. name='j_password' /></td>
28. </tr>
29. <tr>
30. <td style="text-align: right"><label for="j_captcha"> 验证码: </label></td>
31. <td>
32. <input type='text' name='j_captcha' class="required"
33. size='5' />
34. <img id="imageF" src="<c:url value="/resource/image.jsp"/>" />
35. <a href="#" id="flashImage">看不清楚换一张</a>
36.
37. </td>
38. </tr>
39. <tr>
40. <td align="right"><input id="_spring_security_remember_me"
41. name="_spring_security_remember_me" type="checkbox" value="true" />
42.
43. </td>
44. <td><label for="_spring_security_remember_me">Remember Me?</label>
45. </td>
46. </tr>
47. <tr>
48. <td colspan="2" style="text-align: center"><input
49. type="submit" name="submit" value="登录" /></td>
50. </tr>
51. </table>
52. </form>
53. </center>
54. <script type="text/javascript">
55.
56. document.f.j_username.focus();
57. if ('${message}' == 1) {
58. alert("用户名或密码错误");
59. }
60.
61. jQuery(function($){
62.
63.
64. $("#flashImage").click(function(){
65.
66. $('#imageF').hide().attr('src','<c:url value="/resource/image.jsp"/>'+ '?'+ Math.floor(Math.random() * 100)).fadeIn();
67. });
68. });
69.
70.
71. </script>
72.
73.
74. </body>
75. </html>
ImageFilter.java
1. package com.piaoyi.common.filter;
2.
3. import java.io.IOException;
4.
5. import javax.servlet.Filter;
6. import javax.servlet.FilterChain;
7. import javax.servlet.FilterConfig;
8. import javax.servlet.ServletException;
9. import javax.servlet.ServletRequest;
10. import javax.servlet.ServletResponse;
11. import javax.servlet.http.HttpServletRequest;
12. import javax.servlet.http.HttpServletResponse;
13.
14. public class ImageFilter implements Filter{
15.
16. @Override
17. public void destroy() {
18. // TODO Auto-generated method stub
19.
20. }
21.
22. @Override
23. public void doFilter(ServletRequest arg0, ServletResponse arg1,
24. FilterChain arg2) throws IOException, ServletException {
25. // TODO Auto-generated method stub
26. HttpServletRequest request = (HttpServletRequest) arg0;
27. HttpServletResponse response = (HttpServletResponse) arg1;
28.
29. String yanzhengm = request.getParameter("j_captcha");
30. String sessionyanz = (String)request.getSession(true).getAttribute("yzkeyword");
31. if(yanzhengm.equals(sessionyanz)){
32. arg2.doFilter(request, response);
33. }else{
34. response.sendRedirect("/login.do");
35. }
36. }
37.
38. @Override
39. public void init(FilterConfig arg0) throws ServletException {
40. // TODO Auto-generated method stub
41.
42. }
43.
44.
45. }
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
}
}
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
1. <%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" pageEncoding="UTF-8"%>
2. <%!
3. Color getRandColor(int fc,int bc){//随机获得颜色,RGB格式
4. Random random = new Random();
5. if(fc>255) fc=255;
6. if(bc>255) bc=255;
7. int r=fc+random.nextInt(bc-fc);
8. int g=fc+random.nextInt(bc-fc);
9. int b=fc+random.nextInt(bc-fc);
10. return new Color(r,g,b);
11. }
12. %>
13. <%
14. //清除缓存,每次访问该页面时都从服务器端读取
15. response.setHeader("Pragma","No-cache");
16. response.setHeader("Cache-Control","no-cache");
17. response.setDateHeader("Expires", 0);
18.
19. // 定义显示图片的宽度和高度
20. int width=60, height=20;
21. BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
22.
23. // 画图画板
24. Graphics g = image.getGraphics();
25.
26. //定义一个随机数
27. Random random = new Random();
28.
29. // 设置画板背景颜色
30. g.setColor(getRandColor(200,250));
31. //设置画板的填充范围
32. g.fillRect(0, 0, width, height);
33.
34. //设置字体
35. g.setFont(new Font("Times New Roman",Font.PLAIN,18));
36.
37. // 设置线条颜色并画线,155条
38. g.setColor(getRandColor(160,200));
39. for (int i=0;i<155;i++)
40. {
41. int x = random.nextInt(width);
42. int y = random.nextInt(height);
43. int xl = random.nextInt(12);
44. int yl = random.nextInt(12);
45. g.drawLine(x,y,x+xl,y+yl);
46. }
47.
48. // 显示数字,4位长度
49. String sRand="";
50. for (int i=0;i<4;i++){
51. String rand=String.valueOf(random.nextInt(10));
52. sRand+=rand;
53. // 设置每个数字的颜色
54. g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
55. //在画板上写数字,起始位置
56. g.drawString(rand,13*i+6,16);
57. }
58.
59. // 保存进session
60. session.setAttribute("yzkeyword",sRand);
61. //System.out.println("yzm:"+sRand);
62.
63.
64. // 显示图片
65. g.dispose();
66.
67. %>
68.
69. <%
70. //转换成一张图片,格式为JPEG
71. ImageIO.write(image, "JPEG", response.getOutputStream());
72. out.clear();//清空缓存的内容。
73.
74. pageContext.pushBody();
75. %>
<%@ 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
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans:beans xmlns="http://www.springframework.org/schema/security"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
4. xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
5. xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
6. xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
7. xmlns:tool="http://www.springframework.org/schema/tool" xmlns:beans="http://www.springframework.org/schema/beans"
8. xsi:schemaLocation="
9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
10. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
11. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
12. http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
13. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
14. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
15. http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
16. http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.1.xsd
17. http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"
18. default-lazy-init="true">
19.
20.
21. <http security="none" pattern="/index.do" />
22.
23.
24. <http auto-config='true' access-decision-manager-ref="accessDecisionManager"
25. access-denied-page="/index.do">
26. <intercept-url pattern="/demo.do*" access="IS_AUTHENTICATED_REMEMBERED" />
27. <intercept-url pattern="/**/*.do*" access="HODLE" />
28. <logout logout-url="/logout.do" invalidate-session="true"
29. logout-success-url="/logout.jsp" />
30. <form-login login-page="/index.do" default-target-url="/frame.do"
31. always-use-default-target="true" authentication-failure-url="/index.do?login_error=1" />
32. <session-management>
33. <concurrency-control max-sessions="1" expired-url="/timeout.jsp"/>
34. </session-management>
35.
36. <remember-me key="jbcpPetStore" />
37. </http>
38.
39.
40.
41. <!-- Automatically receives AuthenticationEvent messages -->
42. <beans:bean id="loggerListener"
43. class="org.springframework.security.authentication.event.LoggerListener" />
44.
45. <authentication-manager erase-credentials="false">
46. <authentication-provider user-service-ref="userService">
47. <password-encoder hash="md5" />
48. </authentication-provider>
49. </authentication-manager>
50.
51. <beans:bean id="userService" class="com.piaoyi.common.security.UserService" />
52.
53. <beans:bean id="accessDecisionManager"
54. class="org.springframework.security.access.vote.AffirmativeBased">
55. <beans:property name="decisionVoters">
56. <beans:list>
57. <beans:bean class="org.springframework.security.access.vote.RoleVoter" />
58. <beans:bean
59. class="org.springframework.security.access.vote.AuthenticatedVoter" />
60. <beans:bean class="com.piaoyi.common.security.DynamicRoleVoter" />
61. </beans:list>
62. </beans:property>
63. </beans:bean>
64. </beans:beans>