目录
简介
分析
代码实现:
测试与运行
简介
验证码是防止有人利用机器人自动批量注册、对特定的注册用户用特定程序暴力激活成功教程方 式进行不断的登录、灌水。因为验证码是一个混合了数字或符号的图片,人眼看起来都费劲, 机器识别起来就更困难。
分析
登录表单很可能遭到模拟登录的暴力激活成功教程攻击,要么轻易获得特定账户的登录信息,要么给服务器增加了大量的负荷。解决的办法,一般就是在登录前给出一个随机的信息(验证码),非法的非 Web 途径登录者会看不到这个验证码,从而让用户安全登录。为防止攻击者破获验证码,需将验证信息作为图像显示在 Web 上。
代码实现:
利用 Servlet 实现一个 4 位的彩色验证码数据。
import java.io.*; import java.awt.*; import java.awt.image.*; import java.util.*; import javax.imageio.*; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/Image") public class Image extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("image/jpeg"); //禁止图像缓存 response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires", 0); HttpSession session=request.getSession(); // 在内存中创建图象 int width=100, height=40; 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,28)); // 随机产生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=""; //准备一个数字加字母字典 String string = "abcdefghijklmnopqrstuvwxyz"; for (int i=0;i<4;i++){ char rand=string.charAt(random.nextInt(string.length())); sRand+=rand; // 将认证码显示到图象中 //调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成 g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110))); g.drawString(Character.toString(rand),13*i+25,30); } // 将认证码存入SESSION session.setAttribute("rand",sRand); // 图象生效 g.dispose(); ServletOutputStream responseOutputStream =response.getOutputStream(); // 输出图象到页面 ImageIO.write(image, "JPEG", responseOutputStream); //以下关闭输入流! responseOutputStream.flush(); responseOutputStream.close(); } //给定范围获得随机颜色 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); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } }
讯享网
写完后保存文件,启动服务器,访问 Servlet 后可以看到页面中生成了一张图片验证码

测试与运行
该 Servlet 仅仅是一个验证码图像,接下来我们用 jsp 编写一个包含该验证码的登录页面

jsp 程序代码如下:
讯享网 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" +request.getServerPort() + path;
%>
<!DOCTYPE HTML>
<html>
<head>
<title>表单验证</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
<style>
div {
width: 240px;
height: 100%;
margin: 30px auto;
}
label {
margin: 5px auto;
height: 22px;
line-height: 22px;
float: left;
}
.input {
margin: 5px auto;
height: 20px;
float: right;
}
#submit {
width: 100px;
height: 35px;
margin: 5px 8px;
}
</style>
</head>
<body>
<div>
<form id="myForm" action="" method="post" autocomplete="off" >
<label>用户名:</label><input class="input" type="text" name="name" placeholder="请输入用户名"><br>
<label>密码:</label><input class="input" type="password" name="password" placeholder="请输入密码"><br>
<div style="margin-top: 10px;">
<div style="height: 10px;width: 200px;margin-bottom: 0px"> </div>
<input style="width: 110px;height: 33px;margin-right: 20px;float: left " type="text" placeholder="图片验证码" name="code">
<img style="float: right" title="看不清?点击切换。" id="changeServletImg" src="<%=basePath%>/Image/Image">
</div>
<input style="margin-left: 140px" id="submit" type="button" value="登录">
</form>
<div id="errorTips" style="text-align: center;font-size: 18px;color: red"></div>
</div>
</body>
<script>
window.onload = function () {
var changeServletImgDOM = document.getElementById('changeServletImg');
//点击图片时改变验证码
changeServletImgDOM.onclick=change;
function change() {
changeServletImgDOM.src="<%=basePath%>/Image/Image?"+new Date().getTime();
};
document.getElementById('submit').onclick = check;
function check () {
//获取表单数据
var name = document.getElementsByName('name')[0].value;
var password = document.getElementsByName('password')[0].value;
var code = document.getElementsByName('code')[0].value;
var formInfo = 'name=' + name + '&password=' + password + '&code=' + code;
var xhr = new XMLHttpRequest();
//设置请求参数
xhr.open("post","Example_13",true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");
//发送请求
xhr.send(formInfo);
// 设置响应 HTTP 请求状态变化的函数
xhr.onreadystatechange = function() {
if (xhr.status == 200 && xhr.readyState == 4) {
if(xhr.responseText == 'OK') {
// 验证成功时跳转页面
location.href = 'loginSuccess.html';
} else {
// 验证失败时给出错误提示
document.getElementById('errorTips').innerText = xhr.responseText;
}
}
}
}
}
</script>
</html>
loginSuccess.html 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>欢迎</title>
</head>
<body>
<h1>登录成功!</h1>
</body>
</html>
由于 jsp 先于 java 执行,导致 jsp 页面图片验证码获取的session值始终是示前一个。
所以无法直接在填写表单的页面完成验证码的验证。
接下来编写一个 Servlet 来接收由 AJAX 发送的表单数据,然后通过 AJAX 完成错误信息的回显,以及页面跳转。
(为了方便,这里用 equals 进行验证,不连接数据库) 【用户名和密码为 admin】
servlet 程序代码如下:
讯享网import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/Example_13")
public class Example_13 extends HttpServlet {
//判断用户是否存在 (为了方便,这里用 equals 进行验证,不连接数据库)
public boolean isAdmin(String name,String password){
//假设用户不存在
boolean isExist = false;
if("admin".equals(name) && "admin".equals(password)) {
isExist = true;
}
return isExist;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
//获取表单数据
String name = req.getParameter("name");
String password = req.getParameter("password");
String code = req.getParameter("code");
//获取图片验证码
HttpSession session = req.getSession();
String rand = (String)session.getAttribute("rand");
//验证图片验证码
if(rand.equals(code)) {
getConnect();
//验证用户名 密码
if(isAdmin(name,password)) {
closeConnect();
out.print("OK");
} else {
out.print("用户名或密码错误!");
}
} else {
out.print("验证码错误,验证失败!");
}
}
}
效果如下:


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/47796.html