注册验证码功能

为什么要有验证码

  • 可以防止:恶意批量注册、恶意破解密码、刷票、论坛灌水
  • 有效防止某个黑客对某一个特定注册用户,用特定程序暴力破解方式进行不断的登陆尝试
  • 确保当前访问的是来自一个人而非机器的操作
  • 添加 CheckCodeServlet.java Servlet,用来生成验证码
  • 就是把别人写好的生成验证码代码拿到自己程序当中用
  • 生成之后放到了全局上下文对象中了,可以在服务端任何地方都可以获取到了就

/**
 * @author: BNTang
 **/
@WebServlet("/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private List<String> words = new ArrayList<String>();

    @Override
    public void init() throws ServletException {
        String path = getServletContext().getRealPath("/WEB-INF/words.txt");
        try {
            BufferedReader reader = new BufferedReader(new FileReader(path));
            String line;
            while ((line = reader.readLine()) != null) {
                words.add(line);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        int width = 120;
        int height = 30;
        BufferedImage bufferedImage = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics graphics = bufferedImage.getGraphics();
        graphics.setColor(getRandColor(200, 250));
        graphics.fillRect(0, 0, width, height);
        graphics.setColor(Color.WHITE);
        graphics.drawRect(0, 0, width - 1, height - 1);
        Graphics2D graphics2d = (Graphics2D) graphics;
        graphics2d.setFont(new Font("宋体", Font.BOLD, 18));
        Random random = new Random();
        int index = random.nextInt(words.size());
        String word = words.get(index);
        int x = 10;
        for (int i = 0; i < word.length(); i++) {
            graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random
                    .nextInt(110), 20 + random.nextInt(110)));
            int jiaodu = random.nextInt(60) - 30;
            double theta = jiaodu * Math.PI / 180;

            char c = word.charAt(i);

            graphics2d.rotate(theta, x, 20);
            graphics2d.drawString(String.valueOf(c), x, 20);
            graphics2d.rotate(-theta, x, 20);
            x += 30;
        }

        request.getSession().setAttribute("checkcode_session", word);
        this.getServletContext().setAttribute("checkCode", word);
        graphics.setColor(getRandColor(160, 200));
        int x1;
        int x2;
        int y1;
        int y2;
        for (int i = 0; i < 30; i++) {
            x1 = random.nextInt(width);
            x2 = random.nextInt(12);
            y1 = random.nextInt(height);
            y2 = random.nextInt(12);
            graphics.drawLine(x1, y1, x1 + x2, x2 + y2);
        }
        graphics.dispose();
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    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);
    }
}
  • 添加词语文件,待会会随机的从里面取词语并且存在全局上下文当中
  • 词语文件内容如下是一个 .txt 文件
行尸走肉
金蝉脱壳
百里挑一
金玉满堂
背水一战
霸王别姬
天上人间
不吐不快
海阔天空
情非得已
满腹经纶
兵临城下
春暖花开
插翅难逃
黄道吉日
天下无双
偷天换日
两小无猜
卧虎藏龙
珠光宝气
簪缨世族
花花公子
绘声绘影
国色天香
相亲相爱
八仙过海
金玉良缘
掌上明珠
皆大欢喜
逍遥法外
生财有道
极乐世界
情不自禁
愚公移山
龙生九子
精卫填海
海市蜃楼
高山流水
卧薪尝胆
壮志凌云
金枝玉叶
四海一家
穿针引线
无忧无虑
无地自容
三位一体
落叶归根
相见恨晚
惊天动地
滔滔不绝
相濡以沫
长生不死
原来如此

编写静态页面

  • web 文件夹下面创建一个 index.jsp 内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册验证码</title>
</head>
<body>
<form action="/ReqistServlet">
    <input type="text" placeholder="请输入验证码" name="code"/>
    <img src="/CheckCodeServlet" onclick="change(this)"/>
    <input type="submit" value="注册"/>
</form>

<script>
    function change(obj) {
        obj.src = "/CheckCodeServlet?time=" + new Date().getTime();
    }
</script>
</body>
</html>
  • 关于 change 方法的详解如下:
  • 点击 img 标签时发送一个请求向 CheckCodeServlet 中再次获取一个新的图片
  • 拼接一个日期的原因是因为浏览器有缓存,每次请求的参数不一样,就不会有缓存

编写判断验证码是否正确的Servlet

  • 步骤如下:
  1. 设置响应编码
  2. ServletContext 当中获取之前生成的正确验证码
  3. 在获取传入的验证码请求参数
  4. servletContext 当中取出之前存放的验证码
  5. 把接收的验证码与取出的验证码时行比较
  6. 相同时,显示成功
  7. 不同时,显示失败,隔 3 秒钟跳转到输入验证码的界面
/**
 * @author: BNTang
 **/
@WebServlet("/ReqistServlet")
public class ReqistServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        ServletContext servletContext = this.getServletContext();

        String code = request.getParameter("code");

        String Oricode = (String) servletContext.getAttribute("checkCode");

        if (code.equals(Oricode)) {
            response.getWriter().write("验证码正确");
        } else {
            response.getWriter().write("验证码错误,请重新输入验证码");
            response.setHeader("refresh", "3;url=/index.jsp");
        }
    }
}
  • 启动服务器访问页面,如下图效果:

  • 输入正确的验证码点击注册,效果图如下:

  • 输入错误的你自行验证即可,它会隔 3 秒刷新一下
posted @ 2020-10-24 15:44  BNTang  阅读(321)  评论(0编辑  收藏  举报