前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >App扫码登录Web端功能实现

App扫码登录Web端功能实现

作者头像
用户8889406
发布2023-03-05 15:24:59
1.3K0
发布2023-03-05 15:24:59
举报
文章被收录于专栏:小呙同学

大致流程图

流程图
流程图

1.服务端生成二维码(图中的1,2,3,4步)

后端通过下载页面URL与随机生成的UUID拼接成一个字符串,利用hutool工具包的生成二维码方法生成一个二维码。

利用下载页面URL的好处就是:自己的App扫码可以获取URL后面拼接的参数进行下一步逻辑操作。其他的App,例如QQ扫码就可以根据URL直接跳转到公司App的下载页面。

同时创建二维码信息实例对象qrCode,赋值二维码状态为0(待扫描),token为" "。

使用UUID做Key,qrCode做Value,过期时间为1小时(这个地方待确定),存储到redis中。

代码语言:javascript
复制
/**
 * 生成二维码
 *
 * @return {@link RApp}<{@link ?}>
 */
@GetMapping("/generateQrCode")
public ModelAndView generateQrCode(HttpServletResponse response) {

    //app下载页面链接
    String url = "https://xxx/App/download/";
    //随机值UUID
    String code = UUID.fastUUID().toString();

    try {
        //生成二维码
        String qrStr = String.format("%s?k=%s", url, code);
        ServletOutputStream outputStream = response.getOutputStream();
        BufferedImage bufferedImage = QrCodeUtil.generate(qrStr, QrConfig.create());
        ImageIO.write(bufferedImage, "png", outputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }

    //存储二维码信息到redis中,缓存1小时
    QrCode qrCode = new QrCode();
    //待扫描
    qrCode.setState(0);
    qrCode.setToken("");
    redisService.setCacheObject(code, qrCode, (long) 60 * 60, TimeUnit.SECONDS);

    return null;
}

2.App扫码拿到参数后调用服务端接口(图中的5,6,7,8,9步)

根据App传过来的UUID,去redis中获取qrCode。

如果qrCode 不为空:

判断qrCode.getState()的值: ​ 如果等于2,表示已经登录过了,返回”已在别处登录“提示。 ​ 如果不等于2,生成token,将token存储在内存map中,更新二维码状态为1(已扫描),将新的qrCode更新覆盖到redis中,返回”扫码成功“的提示给App端。

如果qrCode 为空:

表示这个二维码已过期,返回”二维码已失效/过期“提示。

代码语言:javascript
复制
/**
  * token存储map
  */
private static final Map<String, String> TOKEN_MAP = new ConcurrentHashMap<>();

/**
 * 已扫描,并生成token
 *
 * @param uuid uuid
 * @return {@link RApp}<{@link ?}>
 */
@GetMapping("/generateToken")
public RApp<?> generateToken(String uuid) {
    QrCode qrCode = redisService.getCacheObject(uuid);
    if (qrCode != null) {
        if (qrCode.getState() != 2) {
            //通过base64将UUID转码生成token
            String token = Base64.encode(IdUtils.fastUUID().getBytes(StandardCharsets.UTF_8));
           //存储token至内存中
            TOKEN_MAP.put(uuid, token);
            //更新二维码状态为已扫描
            qrCode.setState(1);
            redisService.setCacheObject(uuid, qrCode);
            return RApp.createBySuccessMsg("扫码成功");
        } else {
            return RApp.createByErrorMsg("已在别处登录");
        }
    }
    return RApp.createByErrorMsg("二维码已失效");
}

3.App确定登录/取消登陆(图中的10,11,12步)

获取App的当前登录用户信息loginAppUser,根据UUID获取redis中的qrCode

如果qrCode不为空:

判断marker的值: ​ marker = 1:更新二维码状态为2(确定登录),从内存map中获取对应的token 判断token是否为空: ​ 不为空,qrCode对象赋值token,然后移除内存map中的token,刷新loginAppUser用户信息(重置token,App用户会被挤掉) ​ 为空,返回”登录异常,请重新扫码“提示 marker = 1:更新二维码状态为3(取消登陆) 将新的qrCode更新覆盖到redis中。

如果qrCode为空:

表示这个二维码已过期,返回”二维码已失效/过期“提示。

代码语言:javascript
复制
/**
 * 确定登录
 *
 * @param marker 标记 (1 确定登录,2 取消登陆)
 * @return {@link RApp}<{@link ?}>
 */
@GetMapping("/sureLogin")
public RApp<?> sureLogin(int marker, String uuid) {
    //获取app用户信息
    LoginAppUser loginAppUser = SecurityAppUtils.getLoginUserErr();
    //获取二维码信息cache
    QrCode qrCode = redisService.getCacheObject(uuid);
    if (qrCode != null) {
        print();//打印map的代码
        if (1 == marker) {
            //更新二维码状态为成功登录
            qrCode.setState(2);
            //从内存中获取token
            String token = TOKEN_MAP.get(uuid);
            if (StrUtil.isNotBlank(token)) {
                qrCode.setToken(token);
                //移除token
                TOKEN_MAP.remove(uuid);
                //刷新令牌有效期
                loginAppUser.setToken(qrCode.getToken());
                loginAppUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
                tokenAppService.refreshToken(loginAppUser);
            } else {
                return RApp.createByError("登录异常,请重新扫码", -1);
            }
        } else {
            //更新二维码状态为取消登陆
            qrCode.setState(3);
        }
        redisService.setCacheObject(uuid, qrCode);
        return RApp.createBySuccess("成功登录");
    }
    return RApp.createByError("二维码已失效", -1);
}

web端轮询查询接口(图中的13,14,15,16步)

web端从获取到二维码之后,就一直调用该接口,监听的qrCode状态做处理。

代码语言:javascript
复制
/**
 * 轮询二维码状态
 *
 * @param uuid uuid
 * @return {@link RApp}<{@link ?}>
 */
@GetMapping("/getQrCodeState")
public RApp<?> pollingQrCodeState(String uuid) {
    QrCode qrCode = redisService.getCacheObject(uuid);
    if (qrCode == null) {
        return RApp.createByErrorMsg("二维码已过期,请重新扫码");
    }
    return RApp.createBySuccess(qrCode);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 大致流程图
  • 1.服务端生成二维码(图中的1,2,3,4步)
  • 2.App扫码拿到参数后调用服务端接口(图中的5,6,7,8,9步)
  • 3.App确定登录/取消登陆(图中的10,11,12步)
  • web端轮询查询接口(图中的13,14,15,16步)
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档