Java Web开发过程中登陆模块的验证码的实现方式总结
作者:死神的丧钟 发布时间:2022-01-29 19:33:16
标签:Java,验证码
验证码及它的作用
验证码为全自动区分计算机和人类的图灵测试的缩写,是一种区分用户是计算机的公共全自动程序,这个问题可以由计算机生成并评判,但是必须只有人类才能解答.可以防止恶意破解密码、刷票、论坛灌水、有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录。
图文验证码的原理
在servlet中随机生成一个指定位置的验证码,一般为四位,然后把该验证码保存到session中.在通过Java的绘图类以图片的形式输出该验证码。为了增加验证码的安全级别,可以输出图片的同时输出干扰线,最后在用户提交数据的时候,在服务器端将用户提交的验证码和Session保存的验证码进行比较。
实现方式总结
1 验证码生成类RandomCode
RandomCode是一个生成验证码的工具类,支持英文和数字验证码,验证码包括英文大小写和数组,其中英文i、o和数字0、1因为容易产生混淆,不包括在生成验证码中。RandomCode支持输出jpg/bmp/png/gif图片格式的验证码。
/**
* RandomCode验证码可以通过静态方法和实例方法生成。
*
* 静态方法:
*
* //生成长度为4的随机验证码
* String code = RandomCode.randomString(4);
*
* //把验证码图片输入到response输出流中
* //图片格式jpg
* OutputStream os = response.getOutputStream();
* RandomCode.write(code, 120, 30, os, "jpg");
*
* 实例方法:
*
* //实例化验证码类
* RandomCode rc = new RandomCode(4);
*
* //把验证码图片输入到response输出流中
* //图片格式jpg
* OutputStream os = response.getOutputStream();
* rc.write(120, 30, os, "jpg");
*
* //获取验证码字符串
* String code = rc.getCode();
*
*/
public class RandomCode {
/**
* 随机验证码字符
*/
private static String base = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
/**
* 随机验证码长度
*/
private int length = 4;
/**
* 验证码字符串
*/
private String code;
/**
* 4位随机验证码
*/
public RandomCode(){
this.code = RandomCode.randomString(this.length);
}
public RandomCode(int length){
if(length > 0){
this.length = length;
}
this.code = RandomCode.randomString(this.length);
}
/**
* 生成验证码图片
* @param width 图片宽度
* @param height 图片高度
* @return
*/
public BufferedImage toImage(int width, int height){
return RandomCode.toImage(this.code, width, height);
}
/**
* 输出验证码图片,默认图片格式jpeg
* @param width
* @param height
* @param os
* @throws IOException
*/
public void write(int width, int height, OutputStream os) throws IOException{
RandomCode.write(code, width, height, os, "jpeg");
}
/**
* 输出验证码图片
* @param width
* @param height
* @param os
* @param format 图片格式,支持jpg/jpeg/bmp/gif/png
* @throws IOException
*/
public void write(int width, int height, OutputStream os, String format) throws IOException{
RandomCode.write(code, width, height, os, format);
}
public int getLength() {
return length;
}
public String getCode() {
return code;
}
/**
* 静态方法
* 生成随机字符串
* @param length 字符串长度
* @return 随机字符串
*/
public static String randomString(int length){
Random random = new Random();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < length; i++){
sb.append(base.charAt(random.nextInt(base.length())));
}
return sb.toString();
}
/**
* 静态方法
* 输出验证码图片
* @param code 验证码字符串
* @param width 图片宽度
* @param height 图片高度
* @param os 图片输出流
* @param format 图片格式,支持jpg/jpeg/bmp/gif/png
* @throws IOException
*/
public static void write(String code, int width, int height, OutputStream os, String format) throws IOException{
BufferedImage image = toImage(code, width, height);
ImageIO.write(image, format, os);
}
/**
* 静态方法
* 输出验证码图片,默认图片格式jpeg
* @param code 验证码字符串
* @param width 图片宽度
* @param height 图片高度
* @param os 图片输出流
* @throws IOException
*/
public static void write(String code, int width, int height, OutputStream os) throws IOException{
write(code, width, height, os, "jpeg");
}
/**
* 静态方法
* 字符串转成验证码图片
* @param code 验证码字符串
* @param width 验证码图片宽度,单位像素
* @param height 验证码图片高度,单位像素
* @return
*/
public static BufferedImage toImage(String code, int width, int height){
//字体大小
int fontSize = (int)Math.ceil(height * 0.9);
if(fontSize < 20){
fontSize = 20;
}
//字体在Y坐标上的位置
int positionY = (int)Math.ceil(height * 0.8);
int lenCode = code.length();
//计算字体宽度
int fontWidth = width / (lenCode + 2);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics g = image.getGraphics();
//图片背景随机颜色
g.setColor(randomColor(new Random(), 200, 250));
g.fillRect(0, 0, width, height);
//设置字体
g.setFont(new Font("Times New Roman", Font.BOLD, fontSize));
//在图片上画纵横交错的线,达到混淆效果
drawLines(g, width, height);
//在图片上画验证码
drawString(g, code, fontWidth, positionY);
g.dispose();
return image;
}
/**
* 静态方法
* 在图片上话位子
* @param g
* @param code 验证码字符串
* @param fontWidth 字体宽度
* @param positionY 字体Y坐标
*/
private static void drawString(Graphics g, String code, int fontWidth, int positionY){
int len = code.length();
Random random = new Random();
for(int i = 0; i < len; i++){
g.setColor(randomColor(random));
g.drawString(String.valueOf(code.charAt(i)), (i + 1) * fontWidth, positionY);
}
}
private static Color randomColor(Random random){
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
return new Color(r, g, b);
}
private static Color randomColor(Random random, int fc, int bc){
if(fc > 255){
fc = 255;
}
if(bc > 255){
bc = 255;
}
int diff = bc-fc;
int r = fc + random.nextInt(diff);
int g = fc + random.nextInt(diff);
int b = fc + random.nextInt(diff);
return new Color(r,g,b);
}
/**
* 静态方法
* 画纵横交错的线
* @param g
* @param width 验证码图片宽度
* @param height 验证码图片高度
*/
private static void drawLines(Graphics g, int width, int height){
Random random = new Random();
//线的数量
int count = ((int)(Math.ceil(random.nextDouble() * 100))) + 100;
for(int i = 0; i < count; i++){
int fc = 160 + (int)Math.ceil(random.nextDouble() * 40);
int bc = 200 + (int)Math.ceil(random.nextDouble() * 55);
g.setColor(randomColor(random, fc, bc));
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(width / 5);
int yl = random.nextInt(height / 5);
g.drawLine(x, y, x + xl, y + yl);
}
}
}
2 Servlet返回验证码
请求路径http://<网站路径>/random/code/servlet
@WebServlet("/random/code/servlet")
public class RandomCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 验证码图片宽度,单位像素
int width = 120;
// 验证码图片高度,单位像素
int height = 30;
// 验证码图片格式
String format = "png";
// 验证码字符长度
int len = 4;
// 设置图片格式
response.setContentType("image/" + format);
// 禁止浏览器缓存图片
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
String code = RandomCode.randomString(len);
// 把图片输出到response输出流
RandomCode.write(code, width, height, response.getOutputStream(), format);
}
}
3 Strust2返回验证码
public class RandomCodeAction extends ActionSupport {
private static final long serialVersionUID = -7515645222798283236L;
/**
* 获取验证码
*/
public void generateCode() {
HttpServletResponse response = ServletActionContext.getResponse();
// 验证码图片宽度,单位像素
int width = 120;
// 验证码图片高度,单位像素
int height = 30;
// 验证码图片格式
String format = "png";
// 验证码字符长度
int len = 4;
// 设置图片格式
response.setContentType("image/" + format);
// 禁止浏览器缓存图片
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
String code = RandomCode.randomString(len);
// 把图片输出到response输出流
try {
RandomCode.write(code, width, height, response.getOutputStream(), format);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Struts2的验证码配置
<package name="pkg-random-code" namespace="/" extends="struts-default">
<action name="randomCode_*" method="{1}" class="com.rhui.web.action.RandomCodeAction"></action>
</package>
请求路径http://<网站路径>/randomCode_generateCode.do
4 SpringMVC返回验证码
请求路径http://<网站路径>/random/code/generate.do
package com.rhui.web.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.rhui.util.RandomCode;
@Controller
@RequestMapping("/random/code")
public class RandomCodeController {
@RequestMapping("/generate.do")
public void generateCode(HttpServletResponse response) {
// 验证码图片宽度,单位像素
int width = 120;
// 验证码图片高度,单位像素
int height = 30;
// 验证码图片格式
String format = "png";
// 验证码字符长度
int len = 4;
// 设置图片格式
response.setContentType("image/" + format);
// 禁止浏览器缓存图片
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
String code = RandomCode.randomString(len);
// 把图片输出到response输出流
try {
RandomCode.write(code, width, height, response.getOutputStream(), format);
} catch (IOException e) {
e.printStackTrace();
}
}
}


猜你喜欢
- 本文实例讲述了C#迷你猜数。分享给大家供大家参考。具体如下:using System; using System.Collections.G
- Flutter自适应瀑布流前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给
- 1.简介使用线程池可以避免线程的频繁创建以及销毁。JAVA中提供的用于实现线程池的API:Executor、ExecutorService、
- FeignClient脱离eureka自定义URL需求Spring Cloud环境中的FeignClient有时候需要调用特定主机的接口,但
- listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明。
- 什么是 Nacos Config在分布式系统中,由于服务数量巨多,为了方便服务 配置文件统一管理,实时更新,所以需要分布式配置中心组件。Sp
- servlet、filter、listener、interceptor之间的区别和联系一、概念1.servlet:servlet是一种运行服
- Gradle和Maven都是当前热门的自动化构建工具。使用Gradle去构建项目,由于没有办法像Maven一样配置Setting文件来修改本
- 前面两篇文章,分别简述了多线程的使用和发展历程,但是使用多线程无法避免的一个问题就是多线程安全。那什么是多线程安全?如何解决多线程安全?本文
- 前言在 Java 中通常对一些方法进行一些注解操作,但是很多注解在 Java 代码上没有问题,如果切换到 Kotlin 上时,如果继续使用这
- 1. 概述官方JavaDocsApi: java.awt.Component,java.awt.Containernull,绝对布局。绝对布
- 先引用using System.Runtime.InteropServices; 的命名空间, 然后在合适的位置加上如下代码就OK。。注意:
- 本文实例为大家分享了Android实现象棋游戏的具体代码,供大家参考,具体内容如下主要是实现两人对战象棋,没有实现人机对战,主要不会判断下一
- 在上一讲中 OkHttp下载文件并带进度条 中,我们知道怎样去下载文件了。那上传文件呢一、编写服务器端在上一讲服务器下新建UploadFil
- 这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较
- 本文实例为大家分享了java实现微信红包的具体代码,供大家参考,具体内容如下要求基于BigDecimal类实现微信红包算法的功能,比如设置红
- 背景Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。Timsort一直
- Java for循环几种写法整理概要:J2SE 1.5提供了另一种形式的for循环。借助这种形式的for循环,可以用更简单地方式来遍历数组和
- Unity Shader学习:裁切效果,供大家参考,具体内容如下之前看到有人问关于物体裁切方面的问题,初学shader的话可能搞得不是很明白
- 目录前言方案一: 数组方案二:HashMap由 key 获取 value由 value 获取 key解决方案三:枚举总结前言开发系统一些状态