Customizing Exclusive QR Code Ideas--Implementing Scavenging Login

Effect demonstration

1.First in natapp Implement Outer Network Mapping(https://natapp.cn)

2.natapp.exe

3.generate token Link (open first) redis)

//Generate a two-dimensional code token link (Generate a two-dimensional code)
http://p5gc9b.natappfree.cc/generateCode

//Browser display QR code
http://p5gc9b.natappfree.cc/getCodeImg?token=736e39d6c1424f4294958353206c1e06

Scanning Web Two-Dimension Codes with QQ or WeChat

 

Decryption of landing principle of mobile QQ and WeChat scanner

  1. Generate a QR code base using java's QR code framework to store this link address

        /updateTokenState?token=uuid

2. How to ensure that QR codes do not allow duplicate problems, just use token without duplication

Keep the token in redis with key:token value status code

Key:token value status code default status 0

0 means no sweep, 1 means swept

How two-dimensional codes are generated

  1. On-line QR code generation ( http://www.liantu.com/)
  2. Generating a google framework in Java
  3. Front-end generation of QR code jquery-qrcode

Generating QR codes in Java

Maven rely on

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <!-- sprinboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--java 2D Code Generation Framework  -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- Integrate redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
    </dependencies>

Core approach

public class BufferedImageLuminanceSource extends LuminanceSource {

    private final BufferedImage image;
    private final int left;
    private final int top;

    public BufferedImageLuminanceSource(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }

        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }

        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    public boolean isCropSupported() {
        return true;
    }

    public LuminanceSource crop(int left, int top, int width, int height) {
        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
    }

    public boolean isRotateSupported() {
        return true;
    }

    public LuminanceSource rotateCounterClockwise() {
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();
        int width = getWidth();
        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }

}
public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // Two-dimensional code size
    private static final int QRCODE_SIZE = 300;
    // LOGO Width
    private static final int WIDTH = 60;
    // LOGO Height
    private static final int HEIGHT = 60;

    public static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // Insert Picture
        QRCodeUtil.insertImage(image, imgPath, needCompress);
        return image;
    }

    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   The file does not exist!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // Compress LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // Draw a reduced graph
            g.dispose();
            src = image;
        }
        // Insert LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        mkdirs(destPath);
        // String file = new Random().nextInt(99999999)+".jpg";
        // ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public  BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        return image;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // When a folder does not exist, mkdirs automatically creates a multilevel directory, unlike mkdir. (mkdir throws an exception if the parent directory does not exist)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        QRCodeUtil.encode(content, imgPath, destPath, false);
    }
    // Noted Method
    /*
     * public static void encode(String content, String destPath, boolean
     * needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath,
     * needCompress); }
     */

    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtil.encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        QRCodeUtil.encode(content, null, output, false);
    }

    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return QRCodeUtil.decode(new File(path));
    }

}

The landing principle of mobile QQ scanner

  1. Generate a QR code where the link holds the Token This is the login status
  2. The front end uses ajax to send requests periodically to check if the token is logged on
  3. Getting the connection should make the token state logged on when the user scans the code

Core Code

@Controller
public class QrCodeController {
    @Autowired
    private RedisUtil redisUtil;

    private String baseImgUrl = "http://p5gc9b.natappfree.cc/updateTokenState?token=";

    /**
     * Provides interface for creating QR codes
     *
     * @return
     */
    @RequestMapping("/generateCode")
    @ResponseBody
    public String generateCode() throws Exception {
        // 1. Generate token
        String token = UUID.randomUUID().toString().replace("-", "");
        // 2. Stored in redis 0 means not swept, 1 means swept
        redisUtil.setString(token, "0");
        // 3. Generate two-dimensional codes
        // Content stored in QR code
        // Picture path embedded in QR code
        String imgPath = "E:/code/code_bg.png";
        // Path and name of generated QR code
        String destPath = "E:/code/" + token + ".png";
        //Generate two-dimensional code
        QRCodeUtil.encode(baseImgUrl + token, imgPath, destPath, true);
        // Resolve 2D Code
        String str = QRCodeUtil.decode(destPath);
        // Print out the parsed content
        return token;
    }

    /**
     * Return the corresponding two-dimensional code from Token
     *
     * @param token
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/getCodeImg", produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public byte[] getCodeImg(String token) throws IOException {
        File file = new File("E:/code/" + token + ".png");
        FileInputStream inputStream = new FileInputStream(file);
        byte[] bytes = new byte[inputStream.available()];
        inputStream.read(bytes, 0, inputStream.available());
        return bytes;
    }

    /**
     * Show the two-dimensional code of the page according to token
     *
     * @param token
     * @param request
     * @return
     */
    @RequestMapping("/")
    public String index(String token, HttpServletRequest request) {
        request.setAttribute("token", token);
        return "index";
    }
    /**
     * Change the status of the token to 1 by user scanner
     *
     * @param token
     * @return
     */
    @RequestMapping("/updateTokenState")
    @ResponseBody
    public String updateTokenState(String token) {
        if (StringUtils.isEmpty(token)) {
            return "token Cannot be empty!";
        }
        // Change the status of the token to 1
        redisUtil.setString(token, "1");
        return "<h1>User Sweep Success!</h1>";
    }

    /**
     * Front end uses timer to check token status
     *
     * @param token
     * @return
     */
    @RequestMapping("/checkToken")
    @ResponseBody
    public Boolean checkToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return false;
        }
        String redisValue = redisUtil.getString(token);
        if (StringUtils.isEmpty(redisValue)) {
            return false;
        }
        if (!redisValue.equals("1")) {
            return false;
        }
        return true;
    }

    @RequestMapping("/sweepCode")
    @ResponseBody
    public String sweepCode() {
        return "Congratulations, Sample landed successfully!";
    }


}

Application-related Configuration

spring:
  http:
    encoding:
      force: true
      charset: UTF-8
  redis:
    host: 127.0.0.1
    port: 6379
    #    password: 123456
  freemarker:
    allow-request-override: false
    cache: false
    check-template-location: true
    charset: UTF-8
    content-type: text/html; charset=utf-8
    expose-request-attributes: false
    expose-session-attributes: false
    expose-spring-macro-helpers: false
    suffix: .ftl
    template-loader-path: classpath:/templates
server:
  port: 8080

RedisUtils

@Component
public class RedisUtil {
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	// Returns true if key exists and fasle does not exist
	public Boolean setNx(String key, String value, Long timeout) {
		Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
		if (timeout != null) {
			stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
		}
		return setIfAbsent;
	}

	public StringRedisTemplate getStringRedisTemplate() {
		return stringRedisTemplate;
	}

	public void setList(String key, List<String> listToken) {
		stringRedisTemplate.opsForList().leftPushAll(key, listToken);
	}

	/**
	 * Store string type
	 * 
	 * @param key
	 *            key
	 * @param data
	 *            data
	 * @param timeout
	 *            Overtime
	 */
	public void setString(String key, String data, Long timeout) {
		try {

			stringRedisTemplate.opsForValue().set(key, data);
			if (timeout != null) {
				stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
			}

		} catch (Exception e) {

		}

	}

	/**
	 * Open Redis Transaction
	 */
	public void begin() {
		// Open Redis Transaction Permissions
		stringRedisTemplate.setEnableTransactionSupport(true);
		// Open Transaction
		stringRedisTemplate.multi();

	}

	/**
	 * Submit Transaction
	 */
	public void exec() {
		// Transaction committed successfully
		stringRedisTemplate.exec();
	}

	/**
	 * Rollback Redis Transaction
	 */
	public void discard() {
		stringRedisTemplate.discard();
	}

	/**
	 * Store string type
	 * 
	 * @param key
	 *            key
	 * @param data
	 *            data
	 */
	public void setString(String key, String data) {
		setString(key, data, null);
	}

	/**
	 * Query string type based on key
	 * 
	 * @param key
	 * @return
	 */
	public String getString(String key) {
		String value = stringRedisTemplate.opsForValue().get(key);
		return value;
	}

	/**
	 * Delete key based on corresponding key
	 * 
	 * @param key
	 */
	public Boolean delKey(String key) {
		return stringRedisTemplate.delete(key);

	}
}

index.ftl

<h1>Scan the QR code for code-sweeping landing</h1>

<img src="getCodeImg?token=${token}">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
    function checkToken() {
        // alert('1000');
        $.ajax({
            url: "checkToken?token=${token}",
            dataType: "json",
            type: "get",
            async: "false",
            success: function (data) {
                if (data == true) {
                    window.location.href = '/sweepCode';
                }
            }
            ,
            error: function () {

            }
        })
        ;

    }
    setInterval(checkToken, 2000);

</script>

Startup Class

@SpringBootApplication
public class AppQrCode {
    public static void main(String[] args) {
        SpringApplication.run(AppQrCode.class);
    }
}

Tags: Programming Redis Spring Java JQuery

Posted on Thu, 07 Nov 2019 07:23:07 -0800 by Eddie Fisher