前言
近期实现了一个扫码登录的需求,在此之前没有这方面的开发经历,所以接到这个需求的时候还是有点慌的,最终通过查阅网上的资料以及老大的指导下实现了这个功能,目前已经投入使用,实现之后还是蛮兴奋的。特此记录一下实现的过程。
主要原理
怎么实现的呢?首先得了解其中的原理,由于我只提供后台接口,因此只记录后台接口的来龙去脉。先贴张图吧
图是我自己画的,主要原理其实不难,分为如下几个步骤:
1、前端生成一张二维码,使用qrCode.js插件。
2、前端定时请求后台二维码状态,此时在第一次请求的时候可以记录下时间,作为二维码失效时间的对比,数据存储建议使用redis。
3、手机扫描二维码,此时要请求后台接口,将识别出来的二维码值以及登录信息传入后台,改变后台二维码的状态为【已扫描】。
4、服务器给前端返回【已扫描】标识。
5、手机扫描之后出现确认登录按钮,点击确认登录,请求后台,改变二维码的状态为【已确认】。
6、服务器判断二维码状态为【已确认】之后,便根据用户的登录信息返回用户信息,前端渲染个人主页,实现扫码登录。
实现细节
1、定义一个CodeBean实体类
-
public
class CodeBean implements Serializable{
-
-
// 二维码唯一标识
-
private String qrCodeValue;
-
-
// 二维码状态
-
private Integer qrCodeStatus;
-
-
// 用户登录身份证
-
private String token;
-
-
// 二维码生成时间
-
private Long createTime;
-
-
// 员工工号
-
private String workerNo;
-
-
public String getWorkerNo() {
-
return workerNo;
-
}
-
-
public void setWorkerNo(String workerNo) {
-
this.workerNo = workerNo;
-
}
-
-
public Long getCreateTime() {
-
return createTime;
-
}
-
-
public void setCreateTime(Long createTime) {
-
this.createTime = createTime;
-
}
-
-
public String getQrCodeValue() {
-
return qrCodeValue;
-
}
-
-
public void setQrCodeValue(String qrCodeValue) {
-
this.qrCodeValue = qrCodeValue;
-
}
-
-
public Integer getQrCodeStatus() {
-
return qrCodeStatus;
-
}
-
-
public void setQrCodeStatus(Integer qrCodeStatus) {
-
this.qrCodeStatus = qrCodeStatus;
-
}
-
-
public String getToken() {
-
return token;
-
}
-
-
public void setToken(String token) {
-
this.token = token;
-
}
-
}
2、提供给app端的接口
-
public RstUtil loginByCode(CommonRemoteInputBean bean, AppMainBean mainBean) {
-
-
// 参数判断,此处省略
-
-
JSONObject json =
new JSONObject();
-
-
long endTime =
0;
-
long startTime =
0;
-
-
String qRCodeValue = bean.getQrCodeValue();
-
String appName = bean.getAppName();
-
-
// app扫码
-
if (bean.getLoginStep() ==
1) {
-
endTime = System.currentTimeMillis();
-
-
// 判断是否失效
-
CodeBean codeBean = MobileRedisUtil.getCode(qRCodeValue);
-
if (codeBean !=
&& codeBean.getCreateTime() !=
) {
-
startTime = codeBean.getCreateTime();
-
}
-
if (endTime - startTime >= SystemParamConstant.QRCODE_EXPIRETIME) {
-
// 二维码失效
-
MobileRedisUtil.removeCode(qRCodeValue);
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"二维码失效");
-
}
-
-
LoginUserBean userBean = MobileRedisUtil.getLoginUser(mainBean.getEmpNumber(), appName, bean.getToken());
-
-
if (
!= userBean && bean.getToken().equals(userBean.getToken())) {
-
codeBean.setToken(bean.getToken());
-
// 设置二维码状态为已扫描
-
codeBean.setQrCodeStatus(SystemParamConstant.QRCODE_SCANNED);
-
codeBean.setWorkerNo(mainBean.getEmpNo());
-
MobileRedisUtil.saveCode(codeBean);
-
json.put(
"data", codeBean);
-
return RstUtil.getRstUtil(
true, RstUtil.SUCCESS,
"扫描成功!", json);
-
}
else {
-
MobileRedisUtil.removeCode(qRCodeValue);
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"未获取到人员信息!");
-
}
-
}
-
-
// 2、app确认登录
-
if(bean.getLoginStep() ==
2) {
-
-
LoginUserBean userBean = MobileRedisUtil.getLoginUser(mainBean.getEmpNumber(),appName, bean.getToken());
-
CodeBean codeBean = MobileRedisUtil.getCode(qRCodeValue);
-
-
if (
!= userBean && bean.getToken().equals(userBean.getToken())) {
-
if (codeBean !=
&&
-
SystemParamConstant.QRCODE_SCANNED.equals(codeBean.getQrCodeStatus())){
-
codeBean.setQrCodeStatus(SystemParamConstant.QRCODE_CONFIRMED);
-
json.put(
"data", codeBean);
-
MobileRedisUtil.saveCode(codeBean);
-
}
-
}
-
-
return RstUtil.getRstUtil(
true, RstUtil.SUCCESS,
, json);
-
}
-
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"系统异常!");
-
}
3、前端请求的接口
-
/**
-
* 二维码扫码登陆
-
* @param bean
-
* @param mainBean
-
* @return
-
*/
-
private RstUtil qrCodeLogin(CommonRemoteInputBean bean,AppMainBean mainBean){
-
-
-
if(
== MobileRedisUtil.getCode(bean.getQrCodeValue())){
-
CodeBean codeBean =
new CodeBean();
-
codeBean.setCreateTime(System.currentTimeMillis());
-
codeBean.setQrCodeValue(bean.getQrCodeValue());
-
codeBean.setQrCodeStatus(SystemParamConstant.QRCODE_CREATED);
-
MobileRedisUtil.saveCode(codeBean);
-
}
-
-
// 获取是否存在确认登陆信息
-
CodeBean codeBean = MobileRedisUtil.getCode(bean.getQrCodeValue());
-
-
// 如果用户已经点击确认登陆,直接登陆系统
-
if(SystemParamConstant.QRCODE_CONFIRMED.equals(codeBean.getQrCodeStatus())){
-
String appName = bean.getAppName();
-
if(StringUtil.isEmpty(appName)){
-
appName = mainBean.getAppName();
-
}
-
-
try {
-
UserBean user = getLoginUser(codeBean.getWorkerNo() ,
);
-
LoginUserBean userBean = MobileRedisUtil.getLoginUser(user.getWorkerId(),
"jjr", codeBean.getToken());
-
// 保存登陆信息
-
if(userBean !=
&& codeBean.getToken().equals(userBean.getToken())) {
-
// 生成用户登陆token
-
user.setToken(userBean.getToken());
-
userBean.setAppName(appName);
-
userBean.setLoginTime(
new Date());
-
userBean.setImei(mainBean.getImei());
-
userBean.setServiceCode(mainBean.getServiceCode());
-
MobileRedisUtil.saveLoginUser(userBean);
-
}
else {
-
MobileRedisUtil.removeCode(codeBean.getQrCodeValue());
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"登录失败!");
-
}
-
// 删除二维码标识
-
MobileRedisUtil.removeCode(codeBean.getQrCodeValue());
-
-
JSONObject json =
new JSONObject();
-
json.put(
"data", user);
-
-
return RstUtil.getRstUtil(
true, RstUtil.SUCCESS,
"登录成功!", json);
-
}
catch (Exception e) {
-
MobileRedisUtil.removeCode(codeBean.getQrCodeValue());
-
e.printStackTrace();
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"登录失败!");
-
}
-
}
-
-
if(SystemParamConstant.QRCODE_SCANNED.equals(codeBean.getQrCodeStatus())) {
-
return RstUtil.getRstUtil(
true, RstUtil.SUCCESS,
"已扫描,请在手机端确认");
-
}
-
-
if(SystemParamConstant.QRCODE_CREATED.equals(codeBean.getQrCodeStatus())) {
-
return RstUtil.getRstUtil(
true, RstUtil.SUCCESS,
"");
-
}
-
-
return RstUtil.getRstUtil(
false, RstUtil.ERROR,
"暂未确认登录!");
-
}
几个值得注意的地方:
1、二维码失效或使用完必须删除在redis中存储的信息。
2、人员验证需要使用token。
整体就是这样,前端的细节此处就不再详述了,有兴趣的同学可以再评论底下留言,相互探讨下也是十分乐意的