文章目录
- 需求
- 流程
- 交互流程
- 服务交互流程
- 关键思路
- 代码
- 生成二维码,返回给PC展示
- 轮询查询二维码状态
- APP扫码请求
- 登录
- 总结
需求
pc端实现app扫码登录
流程
交互流程
服务交互流程
关键思路
主要问题在于如何识别APP端用户,然后传递给PC端已经登录成功
通过记录标记扫描唯一二维码与用户进行关联,在PC端查询时已绑定通过返回的绑定数据进行登录。这里查询可以使用轮询/长连接,返回绑定的数据主要用于请求返回登录后需要的信息
代码
生成二维码,返回给PC展示
注意返回二维码唯一标识可以进行加码,防止不必要的安全问题
/**
* pc 获取二维码
*
* @return
* @throws IOException
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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如何获取用户信息并达成登录
有问题欢迎一起探讨个人信息联系我.