二维码登录(二)生成二维码

承接上篇博客,本文旨在实现二维码生成的功能,并在redis中存储一个key方便后期APP端扫码时做映射

本文代码git https://github.com/xvshu/qrlogin

1,生成二维码请求action

主要是生成一个唯一标识的key,本次以时间戳为测试key,存入redis,并传回前台,生成相关页面以供APP扫描

 
package com.el.qr.login.web;

import com.el.qr.login.service.RedisQRService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;



/**
 * 首页控制器
 *
 * @author xvshu
 */
@Controller
@RequestMapping("/qr")
public class QRLoginController {
    private static final Logger logger = LoggerFactory.getLogger(QRLoginController.class);

    @Autowired
    private RedisQRService redisQRService;

    @RequestMapping(value = "/login")
    public ModelAndView index() {
        ModelAndView mav = new ModelAndView("qrlogin/qrlogin");
        String codeMark = "xvshu-qrlogin-"+String.valueOf(System.currentTimeMillis());
        mav.addObject("code_mark",codeMark);
        redisQRService.initQRKey(codeMark);
        return mav;
    }

    @RequestMapping(value = "/login/success_check")
    public ModelAndView success_check(String code_mark) {
        ModelAndView mav = new ModelAndView("qrlogin/qrsuccess");
        mav.addObject("code_mark",code_mark);
        return mav;
    }

    @RequestMapping(value = "/login/main")
    public ModelAndView main(String userId) {
        ModelAndView mav = new ModelAndView("qrlogin/qrmain");
        mav.addObject("userId",userId);
        return mav;
    }

    @RequestMapping(value = "/login/success")
    @ResponseBody
    public String success(String code_mark,String userID) {
        String result = "fail";
        if(StringUtils.isNotEmpty(code_mark)&&StringUtils.isNotEmpty(userID)){
            redisQRService.setQRKey(code_mark,userID);
            logger.info("=/login/success=>code_mark:{} userID:{}",code_mark,userID);
            result="success";
        }
        return result;
    }


    @RequestMapping(value = "/login/check")
    @ResponseBody
    public String check(String code_mark) {
        String result = "nouser";
        String qr_value = redisQRService.getQRValue(code_mark);
        logger.info("=/login/check=>code_mark:{} qr_value:{}",code_mark,qr_value);
        if(StringUtils.isNotEmpty(qr_value)){
            result=qr_value;
        }
        return result;
    }


}

2,前台页面

主要应用qrcode.js生成二维码,二维码内容为验证url+唯一标识,方便跳转,并启动两个定时任务,其中一个3秒一次与后台通信,监听是否有用户扫描成功,如果成功则跳转登录成功页面,否则继续等待,第二个定时任务30秒执行一次,如果超过30还未登录成功,则自动暂停所有定时任务,提示用户二维码失效。

效果图:


代码:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">

<!DOCTYPE html>

<html lang="en">
<head>
    <title>翼龙贷扫码登录</title>

    <script type="text/javascript" src="../../common/js/jquery-3.3.1.min.js" ></script>
    <script type="text/javascript" src="../../common/js/jquery.qrcode.min.js" ></script>

    <script type="text/javascript" >

        var int=self.setInterval("check_qrlogin()",2000);

        $(function() {
            var code_mark='${code_mark}';
            $("#code_mark").val(code_mark);
            create_qrcode();
            setTimeout(function(){alert("二维码失效,请刷新页面重新扫码!");clean_qrcode()},30000);
        });

        function check_qrlogin(){
            var code_mark='${code_mark}';
            $.get("/qr/login/check?code_mark="+code_mark,function(data,status){
                if(status=="success"&&data!='nouser'){
                    int=window.clearInterval(int);
                    window.location.href="/qr/login/main?userId="+data;
                }
            });
        }

        function create_qrcode(){
            var code_mark=$("#code_mark").val();
            if(code_mark==null || code_mark==""){
                alert("随机码不能为空!");
                return;
            }
            var baseUrl= "http://172.30.53.250:8080/qr/login/success_check?code_mark=";
            $("#code").text("");
            $('#code').qrcode({
                render : "canvas",//也可以替换为table
                width : 300,
                height : 300,
                text : baseUrl+ code_mark   //二维码内置内容,如果时URL形式一般浏览器会自动加载
            });

        }

        function clean_qrcode(){
            $("#code").html("<h1 style='color:red'>二维码失效,请刷新页面重新扫码!</h1>");
            int=window.clearInterval(int);
        }

    </script>


</head>

<body style="margin: 0">

    <div style="width: 100%;height: 30%;background-color:red;text-align: center">
        <div style="width: 100%;height: 25%;background-color:red;text-align: center"></div>
        <h1 style="font-size: 35px;color: white;margin:auto;">扫码授权平台</h1>
        <p></p>
        <div style="color:white;text-align: center;">二维码30秒后失效,请尽快扫码登录</div>
    </div>

    <div style="width:100%;height:78%;text-align: center;background-color:white;text-align: center">
        <div style="width: 100%;height: 5%;background-color:white;text-align: center"></div>
        <div style="width:100%;height:300px;text-align: center">
            <p style="text-align: center;" class="code" id="code">
            </p>
        </div>
        <p></p><p></p><p></p>
        <div style="width:100%;text-align: center">
            标识码:<input type="text" style="width:200px" id="code_mark" />
        </div>
    </div>



</body>

</html>


二维码失效:


3,redis操作类

此类旨在存储app与后台服务的key-user对应关系,如果有用户扫描到并授权登录成功,则进行key-user对应。

package com.el.qr.login.service;

import com.el.qr.login.utls.QRDateUtils;
import com.el.qr.login.web.QRLoginController;
import com.eloancn.common.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Service
public class RedisQRService {
    private static final Logger logger = LoggerFactory.getLogger(QRLoginController.class);


    @Resource(name = "codisTemplate")
    private HashOperations hashOperations;

    @Resource(name = "codisTemplate")
    private RedisOperations redisOperations;

    private int DAY_LOSS=2;


    private String QR_KEY="qrlogin_";

    public void initQRKey(String qrKey){
        if(!hashOperations.hasKey(initKey(),initKey()+qrKey)){
            hashOperations.put(initKey(),initKey()+qrKey,"");
            logger.info("=RedisQRService.setQRKey=>key:{} file:{} value:{}",initKey(),initKey()+qrKey,"");
            expire(initKey());
        }
    }


    public void setQRKey(String qrKey,String value){
        if(hashOperations.hasKey(initKey(),initKey()+qrKey)&& StringUtils.isEmpty(getQRValue(qrKey))){
            hashOperations.put(initKey(),initKey()+qrKey,value);
            logger.info("=RedisQRService.setQRKey=>key:{} file:{} value:{}",initKey(),initKey()+qrKey,value);
        }
    }


    public String getQRValue(String qrKey){
        return (String)hashOperations.get(initKey(),initKey()+qrKey);
    }

    private String initKey(){
        return QR_KEY+QRDateUtils.getDataString();
    }

    private boolean expire(String key){
        return redisOperations.expire(key,DAY_LOSS, TimeUnit.DAYS);
    }

}


总结:此部分较为容易,旨在对app进行最小的开发,完成二维码登录。



猜你喜欢

转载自blog.csdn.net/xvshu/article/details/80572041
今日推荐