# 实现PC登录页扫描登录功能如何实现
# 参照版本
V8.2SP1
# 需求
项目上需要复用PC登录页的“微信/M3扫码登录”功能,期望把二维码放在客户第三方系统页面展示,供大家扫描登录OA。需要知道这个二维码生成接口及实现。

# 标准实现分析
要进行定制开发,必须了解免登录的实现原理:
# 生成二维码
前端开发,通过F12查找二维码元素,看到这是一个canvas,基于html5渲染。这里看应该是前端js进行的渲染,可以找特征值id="qrcode1",一般都是通过dom操作渲染。

全局搜索qrcode1关键字,可以找到渲染二维码的代码位置:

总结:渲染二维码逻辑为前端显示:
// 一、引入JQuery组件及jquery.qrcode.js(使用别的QR渲染组件也可以)
// 二、实现如下前端代码,随后Jquery("#qrcode1 .qrcode")这个Dom下就有二维码了
var date = new Date();
var dateNumber = date.getTime();
// 记住这个random,这是关键变量
var random="seeyon-" + Math.uuid() + "-" + dateNumber;
var qrcodeRandom = "https://weixin.seeyon.com/mobilehelp.jsp?random=" + random;
$("#random").val(random);
//canvas方式进行图片渲染
$("#qrcode1 .qrcode").empty();
$("#qrcode1 .qrcode").qrcode({
render: isIE8?"table":"canvas", //canvas方式
width: adjustWidth, //宽度
height: adjustHeight, //高度
text: utf16to8(qrcodeRandom) //任意内容
});
// 记住这行代码:每隔1秒向服务器确认是否免登录
setInterval("intervalLogin()", 1000);
# 扫码记录免登
M3或企业微信扫描二维码,能读取到二维码中的random信息,这个random是当前用户很重要的记录信息。
随后M3或企业微信调用OA的免登录接口,记录当前用户进行了免登录:
- LoginResource#loginForWechat(random) 企业微信免登
- LoginResource#loginForM3(random) M3免登
# PC自动登录
上一步是M3通知OA服务器:用户进行了免登,OA服务器记录了免登状态。但此时PC二维码界面是不知道用户免登的,需要有一个动作确认是否有免登状态,如果确认OK,则自动登录,这块实现逻辑就在前端的intervalLogin()方法里:
// 前面二维码渲染处进行了每隔1秒轮询判定是否免登的实现
setInterval("intervalLogin()", 1000);
//轮询请求,防止后台阻塞
function intervalLogin(){
if(sendFlag){
sendFlag = false;
loginForWechat();
}
}
// 真正的轮询方法
function loginForWechat(){
// 从页面获取random信息
var random = $("#random").val();
$.ajax({
async : true,
type: "GET",
url: _ctxPath+"/main.do?method=login4QrCode&random=" + random, //这个请求的意思是判断当前是否进行了免登录操作,如果没有则返回loginError字符串,如果有则返免登录的人员loginName登录名
dataType : 'text',
success : function(data) {
if(data != "loginError" || data == null){
// 如果确认进行了免登录,则模拟登录按钮直接登录
$("#login_username").val(data);
// 这个执行的button上面的点击事件,实际触发的是onclick方法,具体可自行查看前端代码
$("#login_button").click();
} else {
sendFlag = true;
}
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert($.i18n('login.tip.failure'));
}
});
}
依据源码分析,在判定免登录成功后会执行$("#login_button").click();方法,根据方法溯源,可以看到调用链:
$("#login_button").click();
↓
loginButtonOnClickHandler();
↓
doLoginSubmit()
↓
$("#submit_button").click();
↓
<form method="post" action="${path}/main.do?method=login" id="login_form" name="loginform">
<input id="submit_button" type="submit" style="display: none" value="" />
</form>
↓
MainController#login();
↓
QrCodeLoginAuthentication#authenticate(); //免登录认证器
# 实现原理小结
基于以上分析,扫描的完整逻辑为:
1、在PC登录页渲染显示出免登录二维码
2、M3、企业微信APP扫描二维码后,在APP端远程调用OA服务器通知该用户进行了免登录
3、在PC登录页每隔1秒询问OA:用户是否进行了免登录。如果OA服务器返回免登录动作,则PC执行form提交操作登录。
# 第三方页面定制开发解决方案
1、复制一份seeyon\main\login\default\login.jsp登录页的实现源码,把所有能看到的元素全部隐藏起来,只渲染一个二维码,让人感觉这个页面就一个二维码:
- 将背景色、背景图全部干掉
- 将input、button等能看到的Dom元素全部隐藏起来,不要删除
- 将form标签增加target=_blank属性,表示打开新窗口
- 实现免登录二维码渲染操作,保障能看到二维码
-- 增加target="_blank"属性
<form method="post" action="${path}/main.do?method=login" id="login_form" name="loginform" target="_blank">
<input id="submit_button" type="submit" style="display: none" value="" />
</form>
2、第三方页面Iframe的形式访问复制的那份JSP页面,此时第三方页面就只能看到二维码了
3、随后用M3或企业微信扫描二维码,按照原来的业务逻辑会执行submit提交操作,登录打开OA页面
注1:为什么要拷贝一份login.jsp而不是新建一个空白html页面,只引入二维码?
答:因为自动跳转使用了login.jsp里面的很多业务逻辑,包括dom的操作,当然如果你技术能力强,也可以自己实现免登录