`
jdluojing
  • 浏览: 18005 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

Struts2学习笔记(十九) 验证码

 
阅读更多

概述

验证码也是我们在web应用中经常要用到的功能。基本思路就是,我们在服务端动态的生一成张图片,然后将它输出到客户端。图片上包含一些字符信息,我们将这些字符信息事先保存在session中,那么客户端在看到图片之后,将图片上的字符输出到表单中,然后将表单提交。我们接收到表单数据之后,对表单中提交的验证码与session中保存的验证码进行比对,如果相同,那么验证通过。否则,验证失败!采取一些处理。

验证码的主要作用就是用在用户登录上,能有效的防止客户端多次发送登录请求来暴力破解。由于验证码信息是以图片的形式呈现的,因此要想通过程序来识别这些字符还是不太容易的。当然验证码也不是绝对安全的,但是相对来说它的实现比较容易,安全性也相对较高,所以使用的非常广泛。

使用jsp/servlet实现图片验证码

这里我们主要是学习验证码的实现原理,因此就不做的过于复杂了。其实有很多开源的验证码生成库,他们做的比较精密,集成也比较方便,因此有需要的话可以使用第三方的库。为了生成验证码的部分代码能够被重用,我将它单独提取成为一个类。

public class AuthCode {

	private ByteArrayInputStream input;
	private ByteArrayOutputStream output;
	private String code;// 验证码
	private int codeNum;// 验证码字符数量

	private int width;
	private int height;

	// 构造器
	private AuthCode(int width, int height, int codeNum) {
		this.width = width;
		this.height = height;
		this.codeNum = codeNum;

		if (width < 15 * codeNum + 6) {
			this.width = 13 * codeNum + 6;
		}
		if (height < 20) {
			this.height = 20;
		}

		buildImage();
	}

	// 以字符串形式返回验证码
	public String getCode() {
		return code;
	}

	// 以输入流的形式返回验证图片
	public ByteArrayInputStream getIamgeAsInputStream() {
		return input;
	}

	// 以输出流的形式返回验证图片
	public ByteArrayOutputStream getImageAsOuputStream() {
		return output;
	}

	// 创建默认大小的验证码
	public static AuthCode createInstance() {
		return new AuthCode(85, 20, 4);
	}

	// 创建指定大小的验证码
	public static AuthCode createInstance(int width, int height, int codeNum) {
		return new AuthCode(width, height, codeNum);
	}

	// 生成验证码图片
	private void buildImage() {

		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));
		
		// 随机产生150条干扰线,使图象中的认证码不易被其它程序探测到
		g.setColor(getRandColor(160, 200));
		for (int i = 0; i < 150; 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);
		}

		// 取随机产生的认证码
		String codes = "ABCDEFGHJKLMNOPQRSTUVWXYZ23456789";
		String sRand = "";
		for (int i = 0; i < codeNum; i++) {
			String rand = codes.charAt(random.nextInt(codes.length())) + "";
			sRand += rand;
			
			// 将认证码显示到图象中
			g.setColor(new Color(20 + random.nextInt(110), 20 + random
					.nextInt(110), 20 + random.nextInt(110)));
			
			// 将字符串绘制到图片上
			g.drawString(rand, i * (width / codeNum) + 6, (int)((height+12)/2));
		}

		/* 验证码赋值 */
		this.code = sRand;
		
		// 图象生效
		g.dispose();

		try {
			output = new ByteArrayOutputStream();
			ImageOutputStream imageOut = ImageIO
					.createImageOutputStream(output);
			ImageIO.write(image, "JPEG", imageOut);
			imageOut.close();
			input = new ByteArrayInputStream(output.toByteArray());
		} catch (Exception e) {
			System.out.println("验证码图片产生出现错误:" + e.toString());
		}

	}

	// 获取随机颜色
	private Color getRandColor(int fc, int bc) {
		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);
	}

}

然后我们定义一个Servlet专门用于输出验证码:

public class AuthCodeServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		AuthCode code = AuthCode.createInstance();

		req.getSession().setAttribute("authCode", code.getCode());

		resp.getOutputStream()
				.write(code.getImageAsOuputStream().toByteArray());

	}
}

index.jsp

<html>
	<head>
		<title>Auth Code</title>
		<script type="text/javascript">
    	function changeImage(obj){
    		obj.src = "AuthCodeServlet?="+Math.random();
    	}
    	
    </script>
	</head>

	<body>

		<form action="LoginServlet" method="post">
			username:
			<input type="text" name="userName" />
			<br>
			password:
			<input type="password" name="password" />
			<br />
			authcode:
			<input type="text" name="authCode" />
			<img src="AuthCodeServlet" onclick="changeImage(this)" />
			<br>
			<input type="submit" value="submit" />
		</form>


	</body>
</html>

LoginServlet.java

public class LoginServlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		String userName = req.getParameter("userName");
		String password = req.getParameter("password");
		String authCode = req.getParameter("authCode");

		String code = (String) req.getSession().getAttribute("authCode");

		if (authCode != null && authCode.toUpperCase().equals(code)
				&& "hello".equals(userName) && "world".equals(password)) {
			resp.getWriter().println("login success! authCode:"+authCode);
		}else{
			resp.getWriter().println("login failed! authCode:"+authCode);
		}

	}
}

测试:

使用Struts2实现图片验证码

Struts2中有一种名为”stream”类型的Result,我们在学习文件下载的时候已经学习过了。我们已经知道只要我们给它提供一个输入流,只需要设置好相应的ContentType,那么它就会自动将这个输入流输出到浏览器中。那么在这里我们依然可以利用它的这个特性。在上一个例子中的验证码生成类中,提供了一个获取输入流的方法,因此这里我还是使用上面的验证码生成类AuthCode。

AuthCodeAction.java

public class AuthCodeAction extends ActionSupport implements SessionAware {

	private Map<String, Object> session;

	public void setSession(Map<String, Object> session) {
		this.session = session;
	}

	public InputStream getInputStream() {

		AuthCode code = AuthCode.createInstance();
		session.put("authCode", code.getCode());

		return code.getIamgeAsInputStream();

	}

	@Override
	public String execute() throws Exception {

		return SUCCESS;
	}

}

LoginAction.java

public class LoginAction extends ActionSupport implements SessionAware {

	private String userName;
	private String password;
	private String authCode;

	private Map<String, Object> session;

	public void setSession(Map<String, Object> session) {
		this.session = session;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getAuthCode() {
		return authCode;
	}

	public void setAuthCode(String authCode) {
		this.authCode = authCode;
	}

	public Map<String, Object> getSession() {
		return session;
	}

	@Override
	public String execute() throws Exception {

		String code = (String) session.get("authCode");

		if (authCode != null & authCode.toUpperCase().equals(code)) {
			return SUCCESS;
		}
		return INPUT;
	}

}

index.jsp基本保持不变,略了。

struts.xml

<package name="default"namespace="/"extends="struts-default">

<action name="authcode" class="action.AuthCodeAction">

<result name="success" type="stream">

<param name="contentType">image/jpeg</param>

</result>

</action>

<action name="login" class="action.LoginAction">

<result>success.jsp</result>

<result name="input">index.jsp</result>

</action>

</package>

测试:

验证码这块相对来说还算是比较简单。但是如果要做一些比较复杂的验证码的话还是要花不少心思的。这块本来跟Struts2没多大关系,不过既然刚好学到了,也就归如到Struts2中吧。

如有不妥之处,还请路过的老鸟们指正!小弟感激不尽。




分享到:
评论

相关推荐

    struts2学习笔记总结

    本笔记将全面总结Struts2的核心概念、主要功能以及实际开发中的应用。 一、Struts2概述 Struts2是Apache软件基金会下的一个开源项目,它继承了Struts1的优点并解决了其存在的问题,如性能和灵活性。Struts2的核心是...

    Struts2学习笔记

    根据给定的文件信息,以下是对Struts2学习笔记中涉及的关键知识点的详细解析: ### Struts2框架概览 #### MVC模式的理解与演进 Struts2是基于MVC(Model-View-Controller)模式设计的一种Java Web开发框架。在MVC...

    struts2学习笔记(完美总结)——转自OPEN经验库

    Struts2是一个强大的Java web应用程序开发框架,它遵循Model-View-Controller (MVC)设计模式,用于构建可维护性和可扩展性高的企业级应用。本文将深入探讨Struts2的核心概念,包括Action、Result、配置文件、OGNL与...

    struts2 学习重点笔记

    ### Struts2 学习重点知识点总结 #### 一、Struts2 概念与架构 **1.1 Struts2 简介** - **定义**:Struts2 是 Apache 组织提供的一个基于 MVC 架构模式的开源 Web 应用框架。 - **核心**:Struts2 的核心其实是 ...

    张龙圣思园struts2学习笔记word

    张龙圣思园的Struts2学习笔记,无疑为Java开发者提供了一份宝贵的参考资料,它可能涵盖了Struts2的基础概念、核心组件、配置方式以及实战技巧。 首先,让我们深入了解Struts2的核心特性。Struts2是MVC(Model-View-...

    struts2学习笔记.doc

    ### Struts2学习笔记知识点概览 #### 一、环境搭建 **1.1 Struts2简介** - **Struts2概述**:Struts2是一个开源的MVC框架,它结合了Struts 1.x、WebWork和其他一些框架的优点。Struts2的主要目标是简化Web应用程序...

    struts2学习笔记(1)

    ### Struts2学习笔记知识点详解 #### 一、Struts2框架的基本引入步骤 ##### 1. 导入Struts2相关Jar包 在引入Struts2框架时,首先需要将Struts2的相关Jar包导入到项目的类路径中。这些Jar包通常包括核心库以及其他...

    struts2学习笔记3数据类型转换

    struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换struts2学习笔记3数据类型转换

    struts2学习笔记

    struts2学习笔记struts2学习笔记struts2学习笔记

    struts2学习笔记黑马程序员

    ### Struts2学习笔记之文件上传与Ajax开发 #### Struts2文件上传 **文件上传简介** 文件上传是Web应用中常见的功能之一,Struts2框架内置了对文件上传的支持,使得开发者能够轻松地实现这一功能。为了确保文件...

    struts2四天的学习笔记

    13. ** strut2四天笔记**:这份学习笔记可能涵盖了以上所有知识点,包括如何创建Action,配置struts.xml,使用OGNL表达式,处理异常,以及实践中的各种技巧和最佳实践。 在四天的学习过程中,你应该通过实践和理解...

    struts2学习笔记十九(第19讲.Struts2深入探索 续)

    通过以上知识点的学习和实践,你可以更有效地利用Struts2开发高质量的Java Web应用。不过,随着Spring Boot和其他现代框架的兴起,开发者也应关注新技术的发展,以便选择最适合项目需求的工具。

    struts2 学习笔记 实战

    Struts2是一个强大的MVC(Model-View-Controller)框架,它在Java Web开发中扮演着重要的角色。本文将深入探讨Struts2的核心概念,包括Namespace、标签、Action以及它们在实际开发中的应用。 一、Namespace ...

    struts2学习笔记(详细文字)

    structs2很详细的学习笔记,structs2的建造,工作原理,例子,逐步讲解,纯文字的

    struts 2 学习笔记

    在Struts2中,学习笔记通常会涵盖以下几个关键概念: 1. **源代码查看和Javadoc**:开发者可以通过查看源代码来理解Struts2的工作原理,而Javadoc则提供了API文档,帮助理解类和方法的功能。 2. **包(Package)和...

Global site tag (gtag.js) - Google Analytics