Shiro安全框架(Shiro与SpringBoot整合开发)之图片验证码(五)

SpringBoot之整合Shiro(最详细) pom.xml 2.3 创建前端页面 在webapp文件夹中创建index.jsp和login.jsp index.jsp login.jsp 2.4 配置视图信息 application.properties 2.5 解决IDEA冲突问题 JSP 与IDEA 与SpringBoot存在一定的不兼容,修改此配置即可解决 pom.xml 3.2 自定义Realm 在shiro文件夹下创建realm文件夹 3.3 Shiro配置 在config文件夹中创建ShiroConfig.java 3.4 启动测试 输入 阅读详情

这篇博文主要讲解实现图片验证码的实现,之前已经将权限,认证,自带缓存,redis缓存,都实现了,现在我们就来了解一下简单的图片验证码的实现:

首先,我们要来修改一下登录的页面,login.jsp这个页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>后台管理系统</title>
</head>
<body>
<h1>用户登录</h1>
    <form action="${pageContext.request.contextPath}/user/login">
        <input type="text" name="username" placeholder="请输入用户名"><br/>
        <input type="text" name="password" placeholder="请输入密码"><br/>
        请输入验证码:<input type="text" name="code"><img src="${pageContext.request.contextPath}/user/getImage" alt=""><br/>
        <input type="submit" name="立即登录">
    </form>
</body>
</html>

从上面的页面可以看出来,我们加入了一行图片验证码的代码。并且访问了一个后端接口:/user/getImage。

下面我们就来看一下这个后端接口:

    @RequestMapping("/getImage")
    public void getImage(HttpSession session, HttpServletResponse response) {
        //生成验证码
        String code = VerifyCodeUtils.generateVerifyCode(4);
        //验证码放入Session
        session.setAttribute("code",code);
        try {
            ServletOutputStream os = response.getOutputStream();
            response.setContentType("image/png");
            //验证码存入图片
            VerifyCodeUtils.outputImage(220,60,os,code);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

可以看到我们在这个接口中主要就干了两件事,一件事就是利用生成验证码工具类生成一个四位数的验证码,然后将验证码存入session中,并将验证码存入图片当中去。下面我们就来上生成验证码的工具类:

public class VerifyCodeUtils{

    //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
    public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
    private static Random random = new Random();


    /**
     * 使用系统默认字符源生成验证码
     * @param verifySize    验证码长度
     * @return
     */
    public static String generateVerifyCode(int verifySize){
        return generateVerifyCode(verifySize, VERIFY_CODES);
    }
    /**
     * 使用指定源生成验证码
     * @param verifySize    验证码长度
     * @param sources   验证码字符源
     * @return
     */
    public static String generateVerifyCode(int verifySize, String sources){
        if(sources == null || sources.length() == 0){
            sources = VERIFY_CODES;
        }
        int codesLen = sources.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for(int i = 0; i < verifySize; i++){
            verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
        }
        return verifyCode.toString();
    }

    /**
     * 生成随机验证码文件,并返回验证码值
     * @param w
     * @param h
     * @param outputFile
     * @param verifySize
     * @return
     * @throws IOException
     */
    public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
        String verifyCode = generateVerifyCode(verifySize);
        outputImage(w, h, outputFile, verifyCode);
        return verifyCode;
    }

    /**
     * 输出随机验证码图片流,并返回验证码值
     * @param w
     * @param h
     * @param os
     * @param verifySize
     * @return
     * @throws IOException
     */
    public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
        String verifyCode = generateVerifyCode(verifySize);
        outputImage(w, h, os, verifyCode);
        return verifyCode;
    }

    /**
     * 生成指定验证码图像文件
     * @param w
     * @param h
     * @param outputFile
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
        if(outputFile == null){
            return;
        }
        File dir = outputFile.getParentFile();
        if(!dir.exists()){
            dir.mkdirs();
        }
        try{
            outputFile.createNewFile();
            FileOutputStream fos = new FileOutputStream(outputFile);
            outputImage(w, h, fos, code);
            fos.close();
        } catch(IOException e){
            throw e;
        }
    }

    /**
     * 输出指定验证码图片流
     * @param w
     * @param h
     * @param os
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
        int verifySize = code.length();
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Random rand = new Random();
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        Color[] colors = new Color[5];
        Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
                Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
                Color.PINK, Color.YELLOW };
        float[] fractions = new float[colors.length];
        for(int i = 0; i < colors.length; i++){
            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
            fractions[i] = rand.nextFloat();
        }
        Arrays.sort(fractions);

        g2.setColor(Color.GRAY);// 设置边框色
        g2.fillRect(0, 0, w, h);

        Color c = getRandColor(200, 250);
        g2.setColor(c);// 设置背景色
        g2.fillRect(0, 2, w, h-4);

        //绘制干扰线
        Random random = new Random();
        g2.setColor(getRandColor(160, 200));// 设置线条的颜色
        for (int i = 0; i < 20; i++) {
            int x = random.nextInt(w - 1);
            int y = random.nextInt(h - 1);
            int xl = random.nextInt(6) + 1;
            int yl = random.nextInt(12) + 1;
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
        }

        // 添加噪点
        float yawpRate = 0.05f;// 噪声率
        int area = (int) (yawpRate * w * h);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(w);
            int y = random.nextInt(h);
            int rgb = getRandomIntColor();
            image.setRGB(x, y, rgb);
        }

        shear(g2, w, h, c);// 使图片扭曲

        g2.setColor(getRandColor(100, 160));
        int fontSize = h-4;
        Font font = new Font("Algerian", Font.ITALIC, fontSize);
        g2.setFont(font);
        char[] chars = code.toCharArray();
        for(int i = 0; i < verifySize; i++){
            AffineTransform affine = new AffineTransform();
            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
            g2.setTransform(affine);
            g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
        }

        g2.dispose();
        ImageIO.write(image, "jpg", os);
    }

    private static Color getRandColor(int fc, int bc) {
        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);
    }

    private static int getRandomIntColor() {
        int[] rgb = getRandomRgb();
        int color = 0;
        for (int c : rgb) {
            color = color << 8;
            color = color | c;
        }
        return color;
    }

    private static int[] getRandomRgb() {
        int[] rgb = new int[3];
        for (int i = 0; i < 3; i++) {
            rgb[i] = random.nextInt(255);
        }
        return rgb;
    }

    private static void shear(Graphics g, int w1, int h1, Color color) {
        shearX(g, w1, h1, color);
        shearY(g, w1, h1, color);
    }

    private static void shearX(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(2);

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);

        for (int i = 0; i < h1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap) {
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private static void shearY(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(40) + 10; // 50;

        boolean borderGap = true;
        int frames = 20;
        int phase = 7;
        for (int i = 0; i < w1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }

        }

    }
    public static void main(String[] args) throws IOException {
        //获取验证码
        String s = generateVerifyCode(4);
        //将验证码放入图片中
        outputImage(260,60,new File("/Users/chenyannan/Desktop/安工资料/aa.jpg"),s);
        System.out.println(s);
    }
}

上面这就是一个生成验证码的工具类,粘贴直接就可以用。

还有一步操作就是将我们的获取验证码的接口方法要在ShiroConfig这个类中放行:

//1.创建Shiro过滤器
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        Map<String, String> map = new HashMap<>();
        map.put("/login.jsp", "anon");
        map.put("/register.jsp", "anon");
        map.put("/user/getImage", "anon");
        map.put("/index.jsp", "authc");
        shiroFilterFactoryBean.setLoginUrl("/login.jsp");
        shiroFilterFactoryBean.setUnauthorizedUrl("/error.jsp”");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

然后来修改一下我们的登录接口,我们的要求是,首先要先比对验证码是否正确,验证码正确之后才能进行认证的操作。

下面是登录接口:

@RequestMapping("/login")
    public String login(User user, String code, HttpSession session) {
        //比较验证码
        String codes = (String) session.getAttribute("code");
        //不区分大小写比较,比较通过后再登陆成功
        try {
            if (codes.equalsIgnoreCase(code)) {
                UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
                Subject subject = SecurityUtils.getSubject();
                subject.login(token);
                return "redirect:/index.jsp";
            } else {
                throw new RuntimeException("验证码错误");
            }
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        return "redirect:/login.jsp";
    }

从上面修改的登录接口可以看出来首先我们从session中取出code,也就是验证码,然后做一个if判断,调用不区分大小写比较的方法。再将原先的代码放入,则完成。

来看一下效果:

这样我们添加验证码的目的就达成了。

SpringBoot基本操作(七)——SpringBoot整合Shiro权限管理(完整demo+界面) SpringBoot2.0笔记 (一)SpringBoot基本操作——环境搭建及项目创建(有demo) (二)SpringBoot基本操作——使用IDEA打war包发布及测试 (三)SpringBoot基本操作——SpringBoot整合SpringDataJpa(有demo) (四)SpringBoot基本操作——SpringBoot使用RedisTemplate整合Redis(有dem... 阅读详情

相关推荐

【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证

登录和用户认证是一个网站最基本的功能,在这篇博客里,将介绍如何用SpringBoot整合Spring Security + JWT实现登录及用户认证

qq_44709990的博客 4万+

竞争神经网络 python_用python解决kaggles奔驰环保竞争

竞争神经网络 python 介绍 (Introduction) In this part, we’ll do most of the work for this competition: We’ll come up with a good validation technique, we’ll hyperparameter tune a Random Forest, and we’ll also ...

weixin_26719331的博客 625

SpringBoot整合Shiro完成验证码校验

SpringBoot整合Shiro完成验证码校验 上一篇:SpringBoot整合Shiro使用Redis作为缓存 首先编写生成验证码的工具类 package club.qy.datao.utils; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.util.Random; /** * 图形验证码生成 */ public class Ve

编程小白养成手记 1115

明明修改或已经更新了前端项目,但是页面没有改变怎么办

不知道做前端的小伙伴是否有的时候会出现,明明修改了功能的部分代码但是刷新页面后或者上传服务器之后却没有任何改变,无论刷新很多次或者关掉页面重新打开,但是就是不显示新的代码, 那么其中很有可能的一项原因就是缓存问题,页面还是处于未更新的状态,如果是这个原因这么几个小妙(适用于chrome浏览器)招分享给大家: 1.如果不怕麻烦,那么就 更多数据→清除浏览器数据→清楚数据就好了 ps:时间范围最好选不限,否则可能无效 2.如果感觉全部删除很麻烦,还可以F12 打开开发者工具,然后在network中勾选Di

菜鸟Li 3万+

【一】Springboot+Shiro+Mybatis+Thymeleaf实现权限控制和gif验证

Springboot+Shiro+Mybatis+ajax实现权限控制,登陆,gif验证码,记住我等功能

程序猿日记本 1万+

自动识别验证码实现系统自动登录(可扩展实现无人自动化操作,如领取各个平台的优惠券),不依赖第三方可以支持离线识别处理,附源码可直接运行

自动识别验证码实现系统自动登录(可扩展实现无人自动化操作,如领取各个平台的优惠券),不依赖第三方可以支持离线识别处理,附源码可直接运行。

代码讲故事 1511

iview 非空验证_记录 iView 的表单验证

iview表单验证必要设置1. 给 Form 标签用 :model 绑定数据2. 给 Form 标签里面必须添加 ref , 用于最后提交获取 Form 表单的实例3. 给 Form 设置属性 rules :rules4. 给需要验证的每个 FormItem 设置属性 prop , 用于表单验证和绑定属性一致iview验证多个表单问题export default {methods:{this.$r...

weixin_32260275的博客 365

毕业论文管理系统的设计与实现

毕业论文工作是高等学校本科培养阶段的一个重要环节。目前论文管理工作存在着许多问题,例如人工管理极为不便;学生对论文所要撰写的内容并不十分了解,与指导老师的沟通非常不便;老师的指导监督也很难完全到位;手工评审的效率低等。而现有的一些毕业论文信息管理或答辩评审系统只是实现了部分网上交流和评审管理的功能,在答辩评审的自测和项目指标权重等方面都存在着一定的不足。因此,本文设计的毕业论文管理系统采用B/S模式开发。其中,Browser层使用JSP技术开发;

wqq_992250277的博客 3182

iView中表单(动态)Form的校验

iview 动态表单校验

k0933的博客 3200

SurfaceControlViewHost使用介绍

可以看到,主要用途:是把一个进程的View显示到另外一个进程里面。

chadm.xiang 1284

终端效率神器:Tmux 安装与使用全指南

终端效率神器:Tmux 安装与使用全指南

身在被窝_心在编程 1358

一篇适合小白的Shiro教程

Shiro的基本使用Shiro简介什么是ShiroShiro核心架构SubjectSecurityManagerAuthenticatorAuthorizerRealmSessionManagerSessionDAOCacheManagerCryptographyShiro中的认证什么是认证三个概念SubjectPrincipalcredential认证的实现Shiro认证的源码分析Shiro使用自定义Relam实现认证CustomerRealmCustomerRealmAuthenticatorTest测

潮汐先生的专栏 6万+

手把手教你用Matlab实现Copula函数:从理论到代码的完整指南

本文提供了一份在MATLAB中实现Copula函数的完整实战指南。从理解Sklar定理和常见Copula家族(如高斯、t、Clayton)的核心概念出发,详细讲解了数据预处理、边缘分布拟合、概率积分变换等关键步骤。通过具体代码示例,手把手演示了Copula模型的拟合、评估、蒙特卡洛模拟,并进阶应用于金融风险度量(如VaR计算)和条件分布分析,帮助读者掌握这一强大的多变量依赖建模工具。

y9z0a1b的博客 953

【SpringBoot整合系列】SpringBoot整合Shiro——权限控制

SpringBoot整合Shiro权限控制

低调做人,低调编码,神码都是浮云 2452

Vulkan入门系列0- Vulkan与OpenGL的区别

虽然Vulkan和OpenGL都是对GPU的抽象,都能达到相同的功能,但它们的设计理念不同,可以说设计差异是非常之大,由于OpenGL从1992年到现在,已经有30多年的历史,GPU功能日新月异,与当年不可同日而语,在OpenGL保持向下兼容情况下,还要在OpenGL基础上设计一套编程接口显然是不可能的,所以推出了新编程规范Vulkan。另外在一些无窗口的应用中,Vulkan可以有选择的不创建帧缓冲区,比如在数学运算,物理模拟,处理视频流的应用中并不需要窗口,所以Vulkan支持更灵活的应用场景。

GPU全栈博主 4068

【图论】系列(七)图论的中心性度量方法及重要性评价指标

图论中的中心性度量方法是用来衡量图中各个节点(或顶点)相对重要性的指标。

qq_30066733的博客 1075

Shiro整合SpringBoot之图片验证码的实现

Shiro整合SpringBoot之图片验证码的实现 一、生成验证码 1. 使用Hutool生成验证码,引入依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.10</version> </dependency> 2. 开发验证码接口 @Req

weixin_42126028的博客 548

【数据集】1980-2020年(5年)土地利用分类数据-中国科学院

简介1980-2020年每五年土地利用数据-中国科学院

WW、forever的博客 3932

Shiro学习笔记_03:整合SpringBoot项目实战

Shiro 学习笔记 本文基于B站UP主【编程不良人】视频教程【2020最新版Shiro教程,整合SpringBoot项目实战教程】进行整理记录,仅用于个人学习交流使用。 视频链接:https://www.bilibili.com/video/BV1uz4y197Zm 官方文档:http://www.baizhiedu.xin 目录标题Shiro 学习笔记六、整合SpringBoot项目实战6.1 整合思路6.2 配置环境6.3 简单使用6.4 常见过滤器6.5 认证和退出实现6.5.1 登录实现6.5

耿鬼不会笑的博客 1万+

Open3D 机载点云电力线提取【2025最新版】

传统方法实现的机载点云电力线分割提取。博客长期更新,本文最新更新时间为:2025年3月23日。

点云侠的博客 4468

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Shiro整合Springboot之图片验证码实现

Shiro整合Springboot之图片验证码实现开发控制器放行验证码新增验证码工具类开发页面修改认证流程 开发控制器 /** * 验证码方法 */ @RequestMapping("getImage") public void getImage(HttpSession session, HttpServletResponse response) throws IOException { //生成验证码 String code = VerifyCodeUtils.generate

mry6的博客 602

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

SpringBoot整合Shiro

SpringBoot整合Shiro

少年有事问春风 1429

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring Boot 整合 Shiro(三)Kaptcha验证码 附源码

前言 本文是根据上篇《Spring Boot 整合Shiro(二)加密登录与密码加盐处理》进行修改,如有不明白的转上篇文章了解。 1.导入依赖 <!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha --> <dependency> ...

云下的你 1599

Shiro整合SpringBoot项目实战

文章目录6.整合SpringBoot项目实战6.0 整合思路6.1 创建springboot项目6.2 引入shiro依赖6.3 配置shiro环境0.创建配置类1.配置shiroFilterFactoryBean2.配置WebSecurityManager3.创建自定义realm4.配置自定义realm5.编写控制器跳转至index.html6.启动springboot应用访问index7.加入权限控制8.重启项目访问查看6.4 常见过滤器6.5 认证实现1. 在login.jsp中开发认证界面2. 开发

冲出仁川,走出马德里,故事还会再继续 782
上一篇: Shiro安全框架(Shiro与SpringBoot整合开发)缓存(五)Shiro缓存实现(redis缓存)
下一篇: Shiro安全框架与SpringBoot整合以及Thymeleaf模板的整合开发补充
JavaJieRui
博客等级 码龄7年 10粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值