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);
                }
    好记性不如烂笔头
  • 相关阅读:
    poj 1113 Wall 凸包的应用
    NYOJ 78 圈水池 (入门级凸包)
    Monotone Chain Convex Hull(单调链凸包)
    poj Sudoku(数独) DFS
    poj 3009 Curling 2.0(dfs)
    poj 3083 Children of the Candy Corn
    Python join()方法
    通过FISH和下一代测序检测肺腺癌ALK基因融合比较
    华大病原微生物检测
    NGS检测ALK融合大起底--转载
  • 原文地址:https://www.cnblogs.com/codehello/p/12921616.html
Copyright © 2011-2022 走看看