客户端扫码登陆的实现

客户端扫描二维码来实现用户登陆的场景,非常普遍,也是目前比较方便的登陆方式之一。

本篇博客就来说一说实现的思路,以及后端、前端、客户端(Android)的协同,以及一些代码。这篇博客不对ZuulFilter以及token的相关知识做补充说明,如果有疑问,请留下评论。

如何理解这种登陆方式的实现?可以看作是三端借助一个随机字符串 randomStr , 来实现用户信息token的精确传递。

前端 or 后端 生成一个随机数randomStr ,后端根据包含randomStr 的数据(数据内容完全根据系统的需要去设置) e.g.

{randomStr : **************** , auth_path : /app/verify , remark : app need take this random_num and access_token to request auth_path}

然后由此生成二维码(github有相应的工具类 com.google.zxing),并返回给前端。此时后端还需要在redis中新建一个k-v键值对,以randomStr 为key,并设置一个默认值和有效时间。

前端在接受到图片之后,需要做三件事。

1. 展示 ; 2.定时器,过了一定时间提示该二维码失效,然后自动刷新重新获取,或者隐藏(根据需求来定) , 3 .定时器,每秒检查一下后端的redis中,k-v是否有值。

客户端的只需要扫描之后,获取到二维码中包含的信息,携带自身已经获取的token以及二维码中的randomStr 请求接口,在该接口中,将用户信息保存在k-v中即可。

 

下面是主要代码。

后端提供的接口

  • 生成二维码接口
  • 检测redis中是否有值的接口
  • app端的认证接口

1 生成二维码接口

@GetMapping("/produce-qrcode")
@Override
public void produceQrCode(String randomStr)  throws IOException {
	Map<String , String> payloadOnQrCode = new HashMap<>();
	payloadOnQrCode.put("randomStr" , randomStr);
	payloadOnQrCode.put("authApi" , "/identity/verify-on-app");
	payloadOnQrCode.put("remark" , "携带客户端token以及randomStr参数,请求authApi接口即可完成登陆验证.二维码有效期 2 分钟");
	//将qrCode_randomStr作为key , value = "" 保存在redis
	String key = "qrCode_" + randomStr;
	RedisUtil.set(redisTemplate , key , "for record" , 60 * 2);
	String jsonString = JSON.toJSONString(payloadOnQrCode);
	// 生成二维码
	QRCodeUtil.outPutQRCodeByImgUrl(jsonString , httpServletResponse);
}

2 检测redis中是否有值的接口

@PostMapping("/check-qrcode-condition")
@ResponseBody
@Override
public Result checkQrCodeCondition(String randomStr) {
	String key = "qrCode_" + randomStr;
	String redis_value = RedisUtil.get(redisTemplate , key);
	if(StringUtils.isBlank(redis_value)){
		return new Result("qrCode has expired,please refresh");
	}
	if(StringUtils.isNotEmpty(redis_value) && !redis_value.equals("for record")){
		RedisUtil.del(redisTemplate , key);
		// redis_value 即为用户的ID
		User user = userService.findOneById(redis_value);
		return new Result((Object) produceTokenByUser(user));
	}else{
		return new Result();
	}
}

3 app端的认证接口

@PostMapping("/verify-on-app")
@ResponseBody
@Override
public Result verifyOnApp(@RequestBody Map<String , Object> body) {
	String randomStr = body.get("randomStr").toString();
	String token_userId = body.get("token_userId").toString();
	String key = "qrCode_" + randomStr;
	String redis_value = RedisUtil.get(redisTemplate , key);
	if(StringUtils.isEmpty(redis_value)){
		return new Result("二维码已过期,请重新获取二维码");
	}else if(redis_value.equals("for record")){
		// 二维码在有效期之内
		RedisUtil.set(redisTemplate , key , token_userId , 5);// 浏览器轮询 有效时间可以设置的小一点
	}
	return new Result();
}

 

app(Android)中,主要代码(如何扫描二维码 并获取数据,不做说明)

1 发送认证请求

 @Override
    protected void setListener() {
        authorize_button.setOnClickListener((v) ->{
            // 发送验证信息
            new Thread(this::sendVerify).start();
        });
    }

    private void sendVerify(){
        try {
            Map<String , String>  param = new HashMap<>();
            param.put("randomStr" , randomStr);

            URL url = new URL(HttpContents.ZUUL_PATH + auth_path);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.addRequestProperty(ACCESS_TOKEN_KEY , SharePreUtils.getAccessToken(context));// 登陆成功时,保存的用户信息
            httpURLConnection.setUseCaches(false);
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setConnectTimeout(10000);
            httpURLConnection.setReadTimeout(10000);
            DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
            dos.write(JSON.toJSONString(param).getBytes(StandardCharsets.UTF_8));
            dos.flush();
            dos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            finish();
        }
    }

前端

检查redis的代码

function startCheckQrCodeConditionInterval(){
    // 开启定时器
    vg_interval_checkQrCodeCondition = window.setInterval(function(){
        var current_ms = Date.now();
        if(current_ms - vg_lastGetQrCodeTime_ms < 2 * 60 * 1000){
            // 小于两分钟 持续的检查二维码状态
            var check_url = zuul_url + "/identity/check-qrcode-condition";
            var param = {randomStr : vg_qrCode_uuid};
            $.post(check_url , param , function(res){
                if(res.state === 1 && null !== res.data && "" !== res.data){
                    //停止定时器
                    stopRefQrCodeInterval();
                    // 保存获取到的token信息
                    saveToken(res.data);
                    startCheckQrCodeConditionInterval();
                    $.tooltip("扫码成功" , tipShow.normal , true);
                    window.location = "index.html";
                }else if(res.state === 0 && "qrCode has expired,please refresh" === res.message){
                    stopRefQrCodeInterval();
                    stopCheckQrCodeConditionInterval();
                    $.tooltip("二维码已过期,请重新获取!");
                }
            });
        }else{
            clearInterval(vg_interval_checkQrCodeCondition);
            vg_interval_checkQrCodeCondition = null;
        }
    } , delay.short);
}

以上是扫码登陆的简单过程,任何问题,可以留在评论中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>