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日

相关文章

  • java 简单的计算器程序实例代码

    下面我将为你讲解“Java 简单的计算器程序实例代码”的完整攻略。包含以下内容: 需求分析 界面设计 计算逻辑设计 完整代码实现 首先,我们需要分析需求。这个计算器能够进行简单的四则运算即可,主要功能有加减乘除四种运算。然后我们需要考虑一下计算器的界面设计。 界面设计:我们需要使用swing提供的jframe来实现我们的计算器。我们需要使用一系列的jlabe…

    Java 2023年6月15日
    00
  • 微软官方SqlHelper类 数据库辅助操作类 原创

    微软官方的SqlHelper类是一个非常好用的数据库辅助操作类,旨在简化与SQL Server数据库交互的代码和流程。下面我将详细讲解如何使用这个类来进行数据库操作。 SqlHelper类的介绍 SqlHelper类是基于ADO.NET的数据库辅助操作类,使用SqlHelper类可以更加容易地执行SQL语句,无需考虑参数、连接、事务等繁琐的细节。SqlHel…

    Java 2023年5月19日
    00
  • java基于AspectJ(面向切面编程)编码示例分享

    下面我将简要介绍一下关于“Java基于AspectJ编码示例分享”的完整攻略。 了解AspectJ AspectJ是一种基于Java语言的AOP(面向切面编程)框架,它提供了完整的Java编程语言中AOP的支持,可以独立使用,也可以与Spring框架相结合使用。 AspectJ有自己的语法规则和关键字,其中最重要的关键字就是@Aspect。用@Aspect注…

    Java 2023年5月20日
    00
  • SQL 手工注射原理小结

    SQL 手工注射原理小结 SQL注入是一种常见的网络攻击手段之一,它可以通过直接向Web应用程序的数据库服务器发送恶意代码来获取数据库的非法访问权。针对SQL注入攻击中的手工注射原理总结如下: 1. SQL注入的原理 SQL注入是一种基于Web应用程序的安全漏洞,攻击者使用恶意字符序列,在Web应用程序的输入方面插入恶意代码,并使应用程序将恶意代码发送到后端…

    Java 2023年6月15日
    00
  • 基于ajax实现文件上传并显示进度条

    下面是基于ajax实现文件上传并显示进度条的完整攻略: 1. 准备工作 在前端实现基于ajax的文件上传需要以下几个工具/库: FormData对象:用于创建一个表单数据对象,方便把文件和其他数据打包发送到服务器端。 XMLHttpRequest对象:用于创建异步请求,可以通过它向服务器端发送数据。 FileReader对象:用于读取本地文件并把它转换成ba…

    Java 2023年5月20日
    00
  • mybatisPlus自定义批量新增的实现代码

    下面我将详细讲解如何实现mybatisPlus自定义批量新增的实现代码,包括两条示例: 自定义批量新增实现代码 mybatisPlus并不支持批量新增操作,所以需要我们手动实现,下面是具体的代码实现: public interface CustomBatchInsertMapper<T> extends BaseMapper<T> {…

    Java 2023年5月20日
    00
  • SSH框架网上商城项目第6战之基于DataGrid的数据显示

    SSH框架网上商城项目第6战之基于DataGrid的数据显示攻略 前言 DataGrid是EasyUI中极常用的组件之一,提供了方便、美观、易用的表格展示方式,因此在实际Web开发中也具有广泛的应用。 本文将向大家介绍如何基于SSH框架实现基于DataGrid的数据显示。 准备工作 在开始之前,需要准备以下内容: Eclipse IDE JDK 1.8 To…

    Java 2023年6月16日
    00
  • R语言3.6.3安装超详细教程附安装包

    下面是详细的“R语言3.6.3安装超详细教程附安装包”的完整攻略。 准备 首先,你需要下载R语言的安装包。可以前往R官网下载对应版本的R语言安装包。 安装 双击运行下载好的R语言安装包; 选择“ Agree”同意协议; 选择安装位置; 在“Select Components”中,推荐选择默认的安装模式; 此时,“Start Menu Folder”中会出现R…

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