文章目录
- 需求
- 流程
- 交互流程
- 服务交互流程
- 关键思路
- 代码
- 生成二维码,返回给PC展示
- 轮询查询二维码状态
- APP扫码请求
- 登录
- 总结
需求
pc端实现app扫码登录
流程
交互流程
服务交互流程
关键思路
主要问题在于如何识别APP端用户,然后传递给PC端已经登录成功
通过记录标记扫描唯一二维码与用户进行关联,在PC端查询时已绑定通过返回的绑定数据进行登录。这里查询可以使用轮询/长连接,返回绑定的数据主要用于请求返回登录后需要的信息
代码
生成二维码,返回给PC展示
注意返回二维码唯一标识可以进行加码,防止不必要的安全问题
/*** pc 获取二维码** @return* @throws IOException*/@Overridepublic ScanningCodeDto getLoginScanningCode() throws IOException {//两个字段key二维码标识,code 二维码ScanningCodeDto codeDto = new ScanningCodeDto();String primitiveKey = StrKit.uuid();//hutool包构建aes加密SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, ScanningCodeLoginConstant.CODE_SECRET_KEY.getBytes(StandardCharsets.UTF_8));//加密为16进制表示String key = aes.encryptHex(primitiveKey);codeDto.setKey(key);ByteArrayOutputStream baos = new ByteArrayOutputStream();//二维码内容也为加密内容QrCodeUtil.generate(key, 300, 300, null, baos);// 进行Base64编码String code = Base64.encode(baos.toByteArray());baos.flush();codeDto.setCode(code);//redis存储信息,5分钟过期ScanningCodeInfoVo scanningCodeInfoVo = new ScanningCodeInfoVo();scanningCodeInfoVo.setKey(key);scanningCodeInfoVo.setCode(code);scanningCodeInfoVo.setStatus("1");//设置到redis,key和过期时间可以根据自己情况设置redisUtils.set( primitiveKey, scanningCodeInfoVo, 60 * 5);return codeDto;}
二维码包含信息能识别即可,可以是url也可以是标识。返回二维码时同时返回唯一标识来标记查询时是哪个二维码
轮询查询二维码状态
/*** 查询二维码状态** @param key 二维码唯一标识* @return*/@Overridepublic ScanningCodeStatusDto getScanningCodeStatus(String key) {//解密为字符串SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, ScanningCodeLoginConstant.CODE_SECRET_KEY.getBytes(StandardCharsets.UTF_8));String primitiveKey = aes.decryptStr(key, CharsetUtil.CHARSET_UTF_8);//查询redis二维码信息ScanningCodeInfoVo scanningCodeInfoVo = (ScanningCodeInfoVo) redisUtils.get(primitiveKey);if (Objects.isNull(scanningCodeInfoVo)) {//返回已过期throw new Exception("二维码已过期");}//成功后登录String status = scanningCodeInfoVo.getStatus();ScanningCodeStatusDto codeStatusDto = new ScanningCodeStatusDto();//已扫描if (Objects.equals("2", status)) {//构建aes加密,加密用户id为16进制表示codeStatusDto.setKey(aes.encryptHex(scanningCodeInfoVo.getUserId() + ":" + scanningCodeInfoVo.getUserName()));codeStatusDto.setStatus("2");return codeStatusDto;}codeStatusDto.setStatus("1");return codeStatusDto;}
有些系统使用长连接,也可以。 注意这里可以加个锁,避免多台设备扫描到一个码。
APP扫码请求
/*** 扫描二维码** @param dto* @return*/@Overridepublic String scan(ScanningCodeDto dto) {//获取对应二维码信息SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, ScanningCodeLoginConstant.CODE_SECRET_KEY.getBytes(StandardCharsets.UTF_8));String primitiveKey = aes.decryptStr(dto.getKey(), CharsetUtil.CHARSET_UTF_8);//查询redis二维码信息ScanningCodeInfoVo scanningCodeInfoVo = (ScanningCodeInfoVo) redisUtils.get(primitiveKey);if (Objects.isNull(scanningCodeInfoVo)) {//返回已过期throw new Exception("二维码已过期");}//成功后登录String status = scanningCodeInfoVo.getStatus();if (Objects.equals("2", status)) {//二维码已经使用throw new Exception("二维码已经使用");}//标记二维码信息,标记状态已经使用scanningCodeInfoVo.setStatus("2");scanningCodeInfoVo.setUserId(teasUserSession.getUserId());scanningCodeInfoVo.setUserName(teasUserSession.getUserName());//修改redis中二维码信息redisUtils.set(primitiveKey, scanningCodeInfoVo, 60 * 5);//返回二维码情况return ”登陆成功“;}
登录
轮询查询到已经扫描并且获取到用户信息后,几个方案都可以
- 调用特定的登录接口进行登录,通过返回的key包含的加密信息进行登录(我这里的使用)
- 轮询接口查询到已经扫码,获取用户信息直接后台登录
- 返回加密后的账号密码调用原有的登录接口(和第一种差不多)
根据自己的情况进行处理即可
总结
扫码登录流程大差不差,主要解决的问题
- 谁扫了码,如何去识别用户扫码
- pc如何获取用户信息并达成登录
有问题欢迎一起探讨个人信息联系我.