扫码登录的实现(第一版)

整个流程:

1.pc进入登录页面,点击扫码登录,点击事件向服务器发送请求获取唯一标识,(服务器生成唯一标识,以该标识为key,以创建一个新码对象为value,放入redis)

2.页面根据获取的唯一标识生成二维码(用qrcode.js),然后开始轮询( 将唯一标识发送到服务器,以唯一标识为key,从redis查询对应的码对象,查看二维码(码对象的是否被扫描字段)是否被扫描 )

3.用户用app扫描二维码,识别出唯一标识,(判断用户是否处于登录状态,如果未登录,跳转app登录,如果已登录接着走)并将唯一标识/用户名以及用户uuid(这个字段在用户登录后存入app缓存中)发送到服务器

4.服务器根据传送过来的唯一标识作为key到redis中查询是否有对应的码对象,如果有则将码对象的是否被扫描字段改为true,并将接收到的用户名和用户uuid放入码对象,之后放入redis更新该对象,

5.接下来回看第2步的轮询,这时码对象已经被扫描了,返回success,之后页面接收success,开始发送扫码成功请求(将uuid发过去),后台接收uuid,然后从redis中取出码对象,从中取出用户名和用户uuid,数据库查询用户名以及用户uuid是否对应,如果对应则执行登录逻辑.

接下来是代码

页面:
<button onclick="getCreateScanLoginUuid()">二维码登录</button>
<input type="hidden" id="uuid">
<div class="pc_qr_code" id="qrcode">

</div>
 <div id="result">请使用手机扫码</div>

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

<script type="text/javascript">
var t1 = "";
function getCreateScanLoginUuid(){
	var url = "/qrcontroller/createScanLoginUuid.html";
	$.ajax({
 		url:url,
 		data:{},
 		dataType:'json',//服务器返回json格式数据
 		type:'post',//HTTP请求类型
 		success:function(data){
 			if(data.success == "1"){
 			    var uuid = data.uuid;
 			    $("#uuid").val(uuid);
 				var content =  "scanLogin:uuid="+uuid;
		 		// 设置参数方式
				var qrcode = new QRCode('qrcode', {
				  text: content,
				  width: 256,
				  height: 256,
				  colorDark : '#000000',
				  colorLight : '#ffffff',
				  correctLevel : QRCode.CorrectLevel.H
				});
		
		     
 				window.setInterval(keepPool, 5000);//开启轮询,5秒轮询一次
 			}else if(data.success == "0"){
 				alert("生成二维码失败,请刷新重试");
 			}
 		},
 		error:function(xhr,type,errorThrown){
 			console.log(type+errorThrown);
 			alert("生成二维码失败,请刷新重试!!!");
 		}
 	});
}
  //轮询函数
  function keepPool(){
      var uuid = $("#uuid").val();

      $.get("/qrcontroller/pool.html",{uuid:uuid},function(msg){
      	var res = JSON.parse(msg);
          if(res.successFlag == '1'){
              console.log("扫码成功.....")
              $("#result").html("<font color='red'>扫码成功</font>");
              
              window.clearInterval(t1);//清除定时器
              window.location.href = "/qrcontroller/success.html?uuid="+uuid;//如果扫描成功跳转登录方法,让其登录
          }else if(res.successFlag == '0'){
              $("#result").html(res.msg);
              $("#result").css({
                  "color":"red"
              })
          }
      });
  }


</script>
    /**
	 * 创建一个扫描登录的uuid
	 */
    @
    @RequestMapping("")
	@ResponseBody
	public JSONObject createScanLoginUuid(){
		JSONObject json = new JSONObject();
		try {
			HttpSession session = getRequest().getSession();
			String uuid = UUID.randomUUID().toString();
			ScanPool scanPool = new ScanPool();
			scanPool.setSession(session.getId());//这一步没用
			redisTemplate.boundHashOps(SCAN_LOGIN_HASH).put(uuid, scanPool);//放入redis
			json.put("uuid", uuid);
			json.put("success", "1");
		} catch (Exception e) {
			json.put("success", "0");
			e.printStackTrace();
		}
        return  json ;
	}

    /**这个是手机端扫码时候确认登录,然后发送ajax到这个方法,
	 * 从缓存中查uuid,如果uuid存在,则改变uuid的状态,通过sessionid将uuid和用户绑定到一起
	 * 扫码登录,对应登录成功跳转首页面
	 * @param uuid
	 * @return
	 */
    @RequestMapping("scanLogin")
	@ResponseBody
	public JSONObject scanLogin(){
		String uuid = getRequest().getParameter("uuid");
		String account = getRequest().getParameter("account");
		String accountUuid = getRequest().getParameter("accountUuid");
//		String sessionId= getRequest().getSession().getId();//浏览器请求的
        JSONObject obj = new JSONObject();
        ScanPool pool = (ScanPool)redisTemplate.boundHashOps(SCAN_LOGIN_HASH).get(uuid);
        
        if (pool == null) {//二维码为空则二维码失效
            obj.put("successFlag","0");
            obj.put("msg","该二维码已经失效,请重新获取");
        } else {//表明已经有人扫过码了
        	Long timeOutSecond = 10 * 60 * 1000L;
        	//二维码超时
        	if(System.currentTimeMillis() - pool.getCreateTime() > timeOutSecond){
				redisTemplate.boundHashOps(SCAN_LOGIN_HASH).delete(uuid);
				obj.put("successFlag","0");
		        obj.put("msg","该二维码已经失效,请重新获取");
			}else{
				pool.setAccount(account);
				pool.setAccountUuid(accountUuid);
				pool.scanSuccess();//设置扫码状态为成功
				redisTemplate.boundHashOps(SCAN_LOGIN_HASH).put(uuid, pool);//更新redis
				obj.put("msg","扫码成功!");
				obj.put("successFlag","1");
			}
        }
        
        return obj;
    }


    /**
	 * 轮询二维码是否被扫描
	 * @return
	 */
    @RequestMapping("pool")
    @ResponseBody
	public JSONObject pool(){
		String uuid = getRequest().getParameter("uuid");
        System.out.println("检测[   " + uuid + "   ]是否登录");
        JSONObject obj = new JSONObject();
        ScanPool pool = (ScanPool)redisTemplate.boundHashOps(SCAN_LOGIN_HASH).get(uuid);

        try {
            if (pool == null) {//码已被清除
                // 扫码超时,进线程休眠
                //Thread.sleep(10 * 1000L);//睡10秒
                obj.put("successFlag","0");
                obj.put("msg","该二维码已经失效,请刷新页面重新获取");
                
            } else {//码还在
                //这里得到的ScanPool(时间靠前)和用户使用手机扫码后得到的不是一个,用户扫码后又重新更新了ScanPool对象,
                //并重新放入了redis中,,所以这里要等待上面的计时器走完,才能获得最新的ScanPool
            	boolean scanFlag = pool.getScanStatus();
            	if (scanFlag) {//已经被扫描了,前台跳转登录方法,让其执行登录逻辑
            		// 根据uuid从redis中获取pool对象,得到对应的sessionId,返给页面,通过js存cookie中
            		obj.put("successFlag","1");
            		//obj.put("cname", "SESSIONKEY");
            		//obj.put("cvalue", pool.getSession());
            	} else {
            		obj.put("successFlag","2");
            		obj.put("msg","等待扫描");
            	}
            }
        } catch (Exception e) {
        	obj.put("successFlag","0");
            obj.put("msg","网络错误,请稍后重试");
            e.printStackTrace();
        }
        return obj ;
    }


    /**
	 * 这个是扫码成功后,要跳转到这里执行登录逻辑,然后跳转首页面
	 * @return
	 * @throws IOException 
	 */
    @RequestMapping("success")
	public String success() throws IOException{
		//执行登录逻辑,清除码.......
		HttpServletRequest request = getRequest();
		String uuid = request.getParameter("uuid");
		ScanPool pool = (ScanPool)redisTemplate.boundHashOps(SCAN_LOGIN_HASH).get(uuid);
		String account = pool.getAccount();
		String accountUuid = pool.getAccountUuid();
		redisTemplate.boundHashOps(SCAN_LOGIN_HASH).delete(uuid);
		//因为uuid是唯一的,所以pool.sessionId和request.getSession().getId()的值一定是一样的
		return scanSuccessLogin(request.getSession(),account,accountUuid,request);//登录逻辑
    }
码对象
import java.io.Serializable;

/**
 * 扫描类,创建时间,扫描状态,
 * @author admin
 *
 */
public class ScanPool implements Serializable{
    

    private static final long serialVersionUID = -9117921544228636689L;
    
    
    private Object session ;//其实这个没啥用
    //创建时间  
    private Long createTime = System.currentTimeMillis();  
      
    //扫描状态  
    private boolean scanFlag = false;  
    
    public boolean isScan(){  
        return scanFlag;  
    }  
      
    public void setScan(boolean scanFlag){  
        this.scanFlag = scanFlag; 
    } 

    private String account;
    private String accountUuid;
    
    
    public String getAccountUuid() {
		return accountUuid;
	}

	public void setAccountUuid(String accountUuid) {
		this.accountUuid = accountUuid;
	}

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}


    public synchronized boolean getScanStatus(){  
      if (isScan()){   
         return true;  
       } 
        return false;  
    }  
      
    /** 
     * 扫码之后设置扫码状态 
     * @param token 
     * @param id 
     */  
    public synchronized void scanSuccess(){  
        try{ 
            setScan(true);   
        } catch (Exception e){  
            e.printStackTrace();  
        }  
    }  
      
    public Long getCreateTime()  
    {  
        return createTime;  
    }  
  
    public void setCreateTime(Long createTime)  
    {  
        this.createTime = createTime;  
    }

    public Object getSession() {
        return session;
    }

    public void setSession(Object session) {
        this.session = session;
    }

    

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值