zoukankan      html  css  js  c++  java
  • 验证码功能实现

    最近公司对公司小程序进行安全漏洞检测,发现我们的登录接口存在安全隐患,需要添加图形验证码来进行过滤,要实现图形验证码要考虑两个问题

    1,图片展现的形式

     1)二进制传到前端直接展示

     2)存到一个图片地址,返回url前端直接获取

    2,如何定位 

    后端生成一个key,验证码,存到缓存中,传给前端,前端传验证码,key到后端

    啥也不说了,直接上代码

    ImageVerificationCode.java

    package org.source.dsmh.utils;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    
    import org.apache.commons.lang3.ArrayUtils;
    
    import sun.misc.BASE64Encoder;
    
    
    public class ImageVerificationCode {
    
         private  volatile  static  ImageVerificationCode imageCode;
    
            private  ImageVerificationCode(){}
    
            public  static  ImageVerificationCode getInstance(){
                if(imageCode==null){
                    synchronized (ImageVerificationCode.class){
                        if(imageCode==null){
                            imageCode=new ImageVerificationCode();
                        }
                    }
                }
                return  imageCode;
            }
        private static Random r = new Random();    //获取随机数对象
        //private String[] fontNames = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"};   //字体数组
     
        //验证码数组
       // private static String codes = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        private static String codes = "1234567890";
    
        /**
         * 获取随机的颜色
         *
         * @return
         */
        private Color randomColor() {
            int r = this.r.nextInt(225);  //这里为什么是225,因为当r,g,b都为255时,即为白色,为了好辨认,需要颜色深一点。
            int g = this.r.nextInt(225);
            int b = this.r.nextInt(225);
            return new Color(r, g, b);            //返回一个随机颜色
        }
    
      
    
        /**
         * 获取随机字符串
         *
         * @return
         */
        public  String randomStr() {
            StringBuilder sb=new StringBuilder();
            for(int i=0;i<4;i++) {
                int index = r.nextInt(codes.length());
                char x=codes.charAt(index);
                sb.append(x);
            }         
            return sb.toString();
        }
    
    
        
        public  String createImageWithVerifyCode(int width, int height, String word) throws IOException {
            String png_base64="";
            //绘制内存中的图片
            BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
            //得到画图对象
            Graphics graphics = bufferedImage.getGraphics();
            //绘制图片前指定一个颜色
            graphics.setColor( Color.white);
            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();
                    
            // 定义x坐标
            int x = 5;
            for (int i = 0; i < word.length(); i++) {
                // 随机颜色
                //graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
                graphics2d.setColor(new Color(0,29,38));
                // 旋转 -30 --- 30度
                int jiaodu = random.nextInt(60) - 30;
                // 换算弧度
                double theta = jiaodu * Math.PI / 180;
                // 获得字母数字
                char c = word.charAt(i);
                //将c 输出到图片
                graphics2d.rotate(theta, x, 20);
                graphics2d.drawString(String.valueOf(c), x, 20);
                graphics2d.rotate(-theta, x, 20);
                x += 18;
            }
            //保存验证码
            
            // 绘制干扰线
            graphics.setColor(this.randomColor());
            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();// 释放资源
            ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
            ImageIO.write(bufferedImage, "png", baos);//写入流中
            byte[] bytes = baos.toByteArray();//转换成字节
            BASE64Encoder encoder = new BASE64Encoder();
            png_base64 = encoder.encodeBuffer(bytes).trim();
            png_base64= "data:image/jpeg;base64,"+png_base64;
           // png_base64 = png_base64.replaceAll("
    ", "").replaceAll("
    ", "");//删除 
    
            return png_base64;
        }
    
        
        public static String getRandomString(int length){
           
            Random random=new Random();
            StringBuffer sb=new StringBuffer();
            for(int i=0;i<length;i++){
              int number=random.nextInt(100);
              sb.append(number);
            }
            return sb.toString();
        }
        public static void main(String[] args) throws IOException {
            
            ImageVerificationCode ivc = new ImageVerificationCode();     //用我们的验证码类,生成验证码类对象
            /*
             * String str=ivc.randomStr(); System.out.println(str);
             * System.out.println(ivc.createImageWithVerifyCode(75, 31,str ));
             */
            
            System.out.println(ivc.getRandomString(5));
        }
    }

    LocalAccountPicCodeServiceImpl.java

    package org.source.dsmh.service.impl;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    import org.apache.log4j.Logger;
    import org.source.dsmh.service.LocalDataService;
    import org.source.dsmh.utils.AccountConstant;
    import org.source.dsmh.utils.DataTemplate;
    import org.source.dsmh.utils.ImageVerificationCode;
    import org.source.dsmh.utils.mongodb.LogMsg;
    import org.source.dsmh.utils.redis.RedisOperator;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.alibaba.druid.util.StringUtils;
    import com.alibaba.fastjson.JSONObject;
    
    /****
     * 图片验证码*/
    @Service("local-account-picCode")
    public class LocalAccountPicCodeServiceImpl implements LocalDataService {
    
        private Logger log = Logger.getLogger(LocalAccountPicCodeServiceImpl.class);
    
        @Autowired
        private RedisOperator redisOperator;
    
        public static final String PICCODE_PREFIX = "account:code";
        
        
        
        private final ReentrantLock lock=new ReentrantLock();
    
        @Override
        public DataTemplate localData(String paramJson, String function, String method, String appUser) {
    
            this.log.info(LogMsg.getLogMsgForInfo(function, method, paramJson, method));         
    
            /**
             * @info 完成参数转换
             */
            JSONObject jsonObject = null;
            if (!StringUtils.isEmpty(paramJson)) {
                try {
                    jsonObject = JSONObject.parseObject(paramJson);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error(LogMsg.getLogMsgForError(function, method, paramJson, "", AccountConstant.PARAM_JSON_ERROR),
                            e);
                    return DataTemplate.error(AccountConstant.PARAM_JSON_ERROR);
                }
            } else {
                jsonObject = new JSONObject();
            }
          /**
             * @info 随机生成验证码--将验证码发送至用户手机
             */
            
             lock.lock();
            try {
                    long time=System.currentTimeMillis();
                    String key=time+ImageVerificationCode.getInstance().getRandomString(5);
                    final int width = 75; // 图片宽度
                    final int height = 31; // 图片高度
    
                    String words = ImageVerificationCode.getInstance().randomStr();
                    // 创建验证码图片并返回图片上的字符串
                    String code = ImageVerificationCode.getInstance().createImageWithVerifyCode(width, height, words);
                    log.info("验证码内容: " + words);
                    this.redisOperator.setCache(PICCODE_PREFIX, "code:" + key, words);
                    log.info(LogMsg.getLogMsgForInfo(function, method, PICCODE_PREFIX+":code:"+key+"验证码:"+words, AccountConstant.SUCCESS));    
                    JSONObject result = new JSONObject();
                    result.put("code", code);                                
                    result.put("picCodeKey", key);
                    return DataTemplate.ok(result);            
            } catch (Exception e) {
                e.printStackTrace();
                log.error(LogMsg.getLogMsgForError(function, method, paramJson, "", "获取验证码失败"), e);
                return DataTemplate.error("获取验证码失败");
            }finally {
                lock.unlock();
            }
    
        }
    }

     LocalAccountLoginvalidateServiceImpl.java

      String picCode=jsonObject.getString("picCode");
        if (StringUtils.isEmpty(picCode)){
                return DataTemplate.error("验证码不能为空");
           }
          String picCodeKey=jsonObject.getString("picCodeKey");             try {
                                                                
                    //获取缓存中验证码值,判断验证码是否正确
                     String valid = this.redisOperator.getCache(PICCODE_PREFIX, "code:" + picCodeKey);
                     
                      if (StringUtils.isEmpty(picCode) || !picCode.equalsIgnoreCase(valid)) {
                            log.error(LogMsg.getLogMsgForError(function, method, paramJson, "缓存验证码:"+valid, AccountConstant.VALID_ERROR_MESSAGE));
                            return DataTemplate.error(AccountConstant.VALID_ERROR_MESSAGE);
                      }                 
                                                        
                } catch (Exception e) {
                    log.error(LogMsg.getLogMsgForError(function, method, paramJson, "", AccountConstant.VALID_ERROR_MESSAGE));
                    return DataTemplate.error(AccountConstant.VALID_ERROR_MESSAGE);
                }
    好记性不如烂笔头
  • 相关阅读:
    keyset与entryset
    solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)
    如何解决This system is not registered with RHN.
    堆和栈的差别(转过无数次的文章)
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
    漫谈并发编程(二):java线程的创建与基本控制
    exosip
    PostgreSQL服务端监听设置及client连接方法
    APK反编译。
  • 原文地址:https://www.cnblogs.com/codehello/p/12921616.html
Copyright © 2011-2022 走看看