springboot登陆页面图片验证码简单的web项目实现

下面我来详细讲解“springboot登陆页面图片验证码简单的web项目实现”的完整攻略。

简介

本项目是一个基于Spring Boot框架的简单web项目,使用图片验证码来保护用户登录页面,防范恶意攻击和爆破。

实现步骤

第一步:新建Spring Boot项目

首先,我们需要新建一个Spring Boot项目,以便进行后续的开发。在创建项目时需要注意选择Web和Thymeleaf模板引擎。

第二步:添加验证码相关依赖

pom.xml文件中添加以下依赖:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>3.10.2</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
    <version>1.0.0</version>
</dependency>

这里我们使用了阿里云提供的短信验证码服务。

第三步:编写验证码生成类

新建一个VerifyCodeUtils类,用于生成随机验证码图片,并将验证码保存在Session中。
代码示例:

public class VerifyCodeUtils {
    private static final String VERIFY_CODES = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * 生成随机验证码图片,并将验证码存储在session中
     *
     * @param width    图片宽度
     * @param height   图片高度
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     * @param length   验证码长度
     * @throws IOException
     */
    public static void generateImage(int width, int height, HttpServletRequest request, HttpServletResponse response, int length) throws IOException {
        String verifyCode = generateVerifyCode(length);

        // 将验证码存储在Session中
        HttpSession session = request.getSession();
        session.setAttribute("verifyCode", verifyCode);

        response.setContentType("image/jpeg");

        //禁止图片缓存
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", -1);

        OutputStream out = response.getOutputStream();
        BufferedImage image = createImage(width, height, verifyCode);
        ImageIO.write(image, "JPEG", out);
        out.flush();
        out.close();
    }

    /**
     * 生成随机验证码
     *
     * @param length 验证码长度
     * @return 验证码字符串
     */
    public static String generateVerifyCode(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(VERIFY_CODES.charAt(new Random().nextInt(VERIFY_CODES.length())));
        }
        return sb.toString();
    }

    /**
     * 创建验证码图片
     *
     * @param width        图片宽度
     * @param height       图片高度
     * @param verifyCode   验证码字符串
     * @return BufferedImage对象
     */
    public static BufferedImage createImage(int width, int height, String verifyCode) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();

        // 绘制背景
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);

        // 绘制干扰线
        Random r = new Random();
        for (int i = 0; i < 10; i++) {
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
            int x1 = r.nextInt(width);
            int y1 = r.nextInt(height);
            int x2 = r.nextInt(width);
            int y2 = r.nextInt(height);
            g.drawLine(x1, y1, x2, y2);
        }

        // 绘制验证码
        Font font = new Font("Arial", Font.BOLD, height - 4);
        g.setFont(font);
        for (int i = 0; i < verifyCode.length(); i++) {
            char c = verifyCode.charAt(i);
            g.setColor(new Color(r.nextInt(80), r.nextInt(80), r.nextInt(80)));
            g.drawString(String.valueOf(c), (i + 1) * width / (verifyCode.length() + 1), height - 4);
        }

        return image;
    }
}

第四步:编写发送短信验证码类

新建一个SmsUtils类,用于发送短信验证码。
代码示例:

public class SmsUtils {
    private static final String ACCESS_KEY_ID = "xxxx";         // 你自己的ACCESS_KEY_ID
    private static final String ACCESS_KEY_SECRET = "xxxx";     // 你自己的ACCESS_KEY_SECRET
    private static final String SIGN_NAME = "Aliyun短信测试专用"; // 在阿里云申请的短信签名
    private static final String TEMPLATE_CODE = "SMS_0000001";  // 在阿里云申请的短信模板编号

    /**
     * 发送短信验证码
     *
     * @param phone    手机号码
     * @param verifyCode 验证码
     * @return 发送结果
     * @throws ClientException
     */
    public static SendSmsResponse sendSms(String phone, String verifyCode) throws ClientException {
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);
        SendSmsRequest request = new SendSmsRequest();
        request.setPhoneNumbers(phone);     // 设置手机号码
        request.setSignName(SIGN_NAME);     // 设置短信签名
        request.setTemplateCode(TEMPLATE_CODE); // 设置短信模板编号
        request.setTemplateParam("{\"code\":\"" + verifyCode + "\"}"); // 设置模板参数:验证码
        SendSmsResponse response = client.getAcsResponse(request);
        return response;
    }
}

第五步:添加验证码处理器

新建一个VerifyCodeController类,用于处理验证码相关操作。
代码示例:

@Controller
public class VerifyCodeController {

    @GetMapping("/verifyCode")
    public void verifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        VerifyCodeUtils.generateImage(100, 40, request, response, 4);
    }

    @GetMapping("/sendVerifyCode")
    @ResponseBody
    public String sendVerifyCode(String phone, HttpServletRequest request) throws ClientException {
        if (StringUtils.isEmpty(phone)) {
            return "请输入手机号码";
        }
        // 生成6位数字验证码
        String verifyCode = String.valueOf((int) ((Math.random() * 9 + 1) * 1_000_000));
        // 发送验证码
        SmsUtils.sendSms(phone, verifyCode);
        // 将验证码存储在Session中
        HttpSession session = request.getSession();
        session.setAttribute("verifyCode", verifyCode);
        return "success";
    }
}

第六步:添加登陆相关代码

LoginController类中添加登陆相关代码。
代码示例:

@Controller
public class LoginController {

    // 登录页面
    @GetMapping("/")
    public String login() {
        return "login";
    }

    // 登录处理
    @PostMapping("/doLogin")
    public String doLogin(String username, String password, String verifyCode, HttpSession session) {
        // 校验验证码
        String code = (String) session.getAttribute("verifyCode");
        if (StringUtils.isEmpty(code) || !code.equalsIgnoreCase(verifyCode)) {
            // 验证码错误
            return "redirect:/?error";
        }
        // 处理登录逻辑
        if ("admin".equals(username) && "123456".equals(password)) {
            return "redirect:/index";
        } else {
            return "redirect:/?error";
        }
    }

    // 首页
    @GetMapping("/index")
    public String index() {
        return "index";
    }

    // 欢迎页面
    @GetMapping("/welcome")
    public String welcome() {
        return "welcome";
    }
}

第七步:添加前端页面

最后,我们需要添加前端页面。以下是login.html页面的代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <style>
        .form-box {
            margin: 50px auto;
            width: 320px;
            background: #fff;
            border-top: 1px solid #eee;
            border-bottom: 1px solid #eee;
            padding: 20px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            text-align: center;
        }

        .form-box h1 {
            font-size: 20px;
            margin-bottom: 20px;
        }

        .form-box input {
            width: 100%;
            height: 40px;
            padding: 0 20px;
            margin-bottom: 20px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 5px;
            outline: none;
        }

        .form-box .verify-code {
            display: inline-block;
            margin-bottom: 20px;
        }

        .form-box .verify-code img {
            cursor: pointer;
            margin-left: 10px;
            vertical-align: middle;
        }

        .form-box button {
            width: 100%;
            height: 40px;
            border: none;
            border-radius: 5px;
            color: #fff;
            background: #4CAF50;
            cursor: pointer;
            outline: none;
        }

        .error {
            color: red;
        }
    </style>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div class="form-box">
    <h1>Login</h1>
    <form action="/doLogin" method="post">
        <input type="text" name="username" placeholder="Username">
        <input type="password" name="password" placeholder="Password">
        <div class="verify-code">
            <input type="text" name="verifyCode" placeholder="Verify Code">
            <img src="/verifyCode" onclick="this.src='/verifyCode?'+Math.random()">
        </div>
        <button type="submit">Login</button>
    </form>
    <div th:if="${param.error}">
        <p class="error">Invalid username or password</p>
    </div>
</div>

<script type="text/javascript">
    $(function () {
        $('.verify-code img').click(function () {
            this.src = '/verifyCode?' + Math.random();
        });

        $('button[type="submit"]').click(function (e) {
            var phone = $('input[name="phone"]').val();
            if (phone && !/^1\d{10}$/.test(phone)) {
                alert('请输入正确的手机号码');
                e.preventDefault();
            }
            var verifyCode = $('input[name="verifyCode"]').val();
            if (verifyCode && verifyCode.length !== 4) {
                alert('验证码长度必须为4位');
                e.preventDefault();
            }
        });

        $('button[name="sendVerifyCode"]').click(function () {
            var phone = $('input[name="phone"]').val();
            if (!phone) {
                alert('请输入手机号码');
                return;
            }
            if (!/^1\d{10}$/.test(phone)) {
                alert('请输入正确的手机号码');
                return;
            }
            $.get('/sendVerifyCode?phone=' + phone, function (data) {
                if (data === 'success') {
                    var count = 60;
                    var timer = setInterval(function () {
                        count--;
                        if (count <= 0) {
                            clearInterval(timer);
                            $('button[name="sendVerifyCode"]').prop('disabled', false).text('发送验证码');
                            return;
                        }
                        $('button[name="sendVerifyCode"]').prop('disabled', true).text(count + '秒后重发');
                    }, 1000);
                } else {
                    alert(data);
                }
            });
        });
    });
</script>
</body>
</html>

至此,整个项目的实现就完成了。我们可以启动该项目并访问http://localhost:8080来体验验证码功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot登陆页面图片验证码简单的web项目实现 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Mybatis Plus 逆向工程介绍

    下面是完整攻略,首先我们来讲解一下Mybatis Plus 逆向工程的概念: 什么是Mybatis Plus逆向工程 Mybatis Plus是一个优秀的Mybatis增强工具,Mybatis Plus逆向工程是一种通过数据库表反向生成对应的Mybatis Plus实体、mapper、mapper.xml等代码文件的技术,可以在一定程度上减少程序员的手动开发…

    Java 2023年5月20日
    00
  • Java中通过Class类获取Class对象的方法详解

    Java中通过Class类获取Class对象的方法详解 在Java编程中,我们常常需要获取某个类的Class对象。获取Class对象的主要方法有以下几种: 使用Class.forName()方法 Class.forName()方法根据传入的类名返回对应的Class对象。 java Class<?> clazz = Class.forName(“j…

    Java 2023年5月26日
    00
  • jQuery Validate验证框架经典大全

    jQuery Validate验证框架是一款针对网页表单验证的插件,它能够轻松实现对用户输入数据的有效性验证和错误提示,并且可轻松定制化。 安装jQuery Validate 安装 jQuery Validate 需要在Web项目中引入jQuery和jQuery Validate插件的代码,如下所示: <head> <script src=…

    Java 2023年6月15日
    00
  • Java之Mybatis的二级缓存

    让我们来详细讲解Java中Mybatis的二级缓存。 什么是Mybatis的二级缓存 Mybatis的二级缓存是一种共享缓存,存放的是数据对象。它可以跨越SQL会话使用,能够减轻数据库的访问压力,提高系统性能。当启用二级缓存后,Mybatis在缓存中存储查询结果对象,并不再每次查询时都向数据库发起SQL请求,从而避免了重复访问数据库。 Mybatis的二级缓…

    Java 2023年5月20日
    00
  • Java编译器用maven打war包出错解决办法

    下面是详细讲解“Java编译器用maven打war包出错解决办法”的完整攻略。 问题描述 当使用Java编译器用maven打war包时,有时会遇到错误,例如“Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile)…

    Java 2023年5月19日
    00
  • Spring Boot + Kotlin整合MyBatis的方法教程

    接下来我将详细讲解“Spring Boot + Kotlin整合MyBatis的方法教程”的完整攻略,过程中包含两条示例说明。 1. 环境准备 在开始整合之前,我们需要先准备好以下环境: JDK 1.8+ Kotlin 1.3+ Spring Boot 2.0+ MyBatis 3.4+ 2. 添加依赖 在开始整合之前,我们需要先在 build.gradle…

    Java 2023年6月1日
    00
  • 详解tomcat各个端口的作用

    详解Tomcat各个端口的作用 本文将详细介绍 Tomcat 各个端口的作用,帮助用户更好地了解 Tomcat 的运行机制。 Tomcat 的端口 Tomcat 有三个最重要的端口,它们分别是: 8080: HTTP 请求的默认端口,用于 Web 应用程序和客户端之间的通信。 8005: Shutdown 端口,用于远程关闭 Tomcat 服务。 8009:…

    Java 2023年5月19日
    00
  • 在服务器端的XSLT过程中的编码问题

    在服务器端执行XSLT转换时,遇到编码问题可能会导致输出与期望的不同。在这种情况下,以下是一些解决问题的步骤: 步骤1:确认XML文件编码和声明 XML文件需要包含字符编码声明。这通常采用以下形式: <?xml version="1.0" encoding="utf-8"?> 这里声明了使用UTF-8编码的…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部