钉钉扫码登录第三方网站官方文档索引:钉钉开放平台 → (任意类型应用)→ 服务端API → 身份验证 → 扫码登录第三方网站,文档中详细的介绍了钉钉扫码登录功能的实现。
以下是大致的实现思路,对比实际项目代码有所改动和删减,具体细节不清楚的地方可以留言提问。
出现需求
由于表单复杂,用户编辑时间过长,提交表单提示token过期失效,需要重新扫码登录,然而用户不希望跳到登录页,更不希望重新编辑表单。
1、token失效,在当前页面弹出登录二维码。
2、如果原用户扫码登录成功可继续编辑表单。
3、如果非原用户扫码登陆成功则更新权限与功能并跳转首页。
解决需求
官方扫码登录后需要页面跳转来传递 loginTmpCode
值,所以不能使用扫码登录第三方网站功能登录,需要自定义扫码登录功能。
开发前准备:
1、应用开发 → 创建H5微应用:免登鉴权。
2、登录接口:鉴权后获取用户信息。
3、H5微应用页面:钉钉端鉴权与登录功能。
4、发起登录的接口:用于发起一个登录,返回登录id。
5、获取登录的接口:用于轮询获取登录状态,返回指定id的登录的状态与信息。
6、设置登录状态接口:设置用户登录状态与信息。
7、安装 qrcode 模块:用来生成登录二维码。
上码
以下为实际项目的实现,代码有所调整。
1、判断token失效,备份原用户信息。
// 请求拦截器
import request from 'axios';
import Bus from './bus';
const resetUser = (urlRedirect, code) => {
let user = sessionStorage.getItem('user');
if (user) {
sessionStorage.setItem('userResign', user);
if (code === '105') {
removeStorage('user');
}
removeStorage('token');
Bus.$emit('userResign');
} else {
if (typeof urlRedirect === 'string' && urlRedirect !== '') {
location.href = urlRedirect;
}
}
};
let instance = request.create();
instance.interceptors.response.use((response) => {
let urlRedirect = '/signIn';
if (response.data && response.data.code) {
if (response.data.code === '101') {
alert('登录超时,请重新登录');
resetUser(urlRedirect, response.data.code);
}
// ...
}
return response;
}, (error) => {
return Promise.reject(error);
});
2、通过生成登录的接口创建登录,获得登录id,生成微应用二维码,并传递登录id。
data() {
return {
icons: {
refresh: '刷新图标'
},
userResign: !1,
signStep: '',
signSrc: ''
};
},
methods: {
createResign() {
return this.$axios.get('创建登录接口');
},
getSignInfo(signId) {
return this.$axios.get('获取登录接口', { params: { signId } });
},
async getSignState(signId) {
if (!signId) {
return;
}
let { data } = await this.getSignInfo(signId);
let { step } = data;
// 设置状态
// "resignCreated" 创建登录id和访问url
// "resignScanned" 用户扫码完成
// "resignSuccess" 登录成功
// "resignTimeout" 执行超时
this.signStep = step;
if (step === 'resignCreated' || step === 'resignScanned') {
clearTimeout(this.timerResign);
this.timerResign = setTimeout(() => {
this.getSignState(signId);
}, 5000);
}
if (step === 'resignSuccess') {
let user = JSON.parse(sessionStorage.getItem('userResign'));
if (data.accessToken) {
// ...
sessionStorage.removeItem('userResign');
sessionStorage.setItem('token', data.accessToken);
sessionStorage.setItem('user', JSON.stringify(data.user));
if (user.userid !== data.user.userid) {
alert('切换登录成功');
location.href = '/';
} else {
alert('重新登录成功');
this.userResign = !1;
}
}
}
},
async resign() {
clearTimeout(this.timerResign);
this.signStep = '';
// 创建登录返回登录id,登录时效一分钟
let { data: { signId } } = await this.createResign();
// 创建成功后,该登录时效内轮询获取登录状态
signId && this.getSignState(signId);
let uri = `微应用地址?signId=${ signId }`;
// 生成微应用地址二维码
this.signSrc = await QRCode.toDataURL(uri, {
width: 210,
height: 210,
margin: 0
});
}
},
created() {
// 用户身份过期
this.$bus.$on('userResign', () => {
this.userResign = !0;
this.$nextTick(this.resign);
});
}
<!-- 登录窗口 -->
<div class="userResign" v-if="userResign">
<div class="viewUserResign">
<div class="viewHead">
重新登录
</div>
<div class="viewContainer">
<div class="viewSign">
<div class="wxCode-box">
<div class="signImg"><img :src="signSrc" alt="" v-if="signSrc" /></div>
<div class="signRefresh" v-show="signStep === 'resignTimeout'">您的二维码已失效,<br>请点击下方刷新按钮</div>
<div class="wxCode-text" v-if="signStep === 'resignScanned'">二维码已扫描</div>
<div class="wxCode-text" v-else>请使用钉钉扫描二维码登录 <span @click.stop="resign"><i v-html="icons.refresh"></i>刷新</span></div>
</div>
</div>
</div>
</div>
</div>
/*
userResign
*/
.userResign {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10000;
background-color: rgba(255, 255, 255, .5);
.viewUserResign {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10000;
width: 658px;
height: 436px;
margin: auto;
background-color: #252525;
border-radius: 4px;
overflow: hidden;
.viewHead {
height: 40px;
border-bottom: 2px solid #424242;
line-height: 40px;
color: #ffffff;
font-size: 18px;
font-weight: normal;
padding: 0 12px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.viewContainer {
padding: 14px;
}
.viewSign {
padding: 20px 0;
background-color: #434343;
border-radius: 4px;
}
.wxCode-box {
position: relative;
width: 300px;
height: 326px;
margin: 0 auto;
padding: 40px 0;
background-color: #ffffff;
border-radius: 4px;
box-sizing: border-box;
.signImg {
display: block;
width: 210px;
height: 210px;
background-color: #ffffff;
margin: 0 auto;
}
.signRefresh {
position: absolute;
top: 40px;
left: 45px;
width: 210px;
height: 210px;
padding-top: 90px;
background-color: rgba(255, 255, 255, 0.9);
text-align: center;
color: #fa5b5b;
line-height: 1.4;
box-sizing: border-box;
}
}
.wxCode-text {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
text-align: center;
color: #898d90;
span {
display: flex;
align-items: center;
margin-left: 5px;
color: #38adff;
cursor: pointer;
svg {
display: block;
margin-right: 1px;
}
}
}
}
}
3、钉钉扫码后访问微应用,接收登录id,通过钉钉JSAPI鉴权。
var userId = '';
var signId = '获取登录id';
var signIn = function(authCode) {
dd.device.notification.showPreloader({
text: '正在加载中..',
showIcon: true
});
this.$axios
.get('登录接口?authCode=' + authCode)
.then(function (result) {
// ...
userId = result.user.userid;
dd.device.notification.hidePreloader();
})
.catch(function(err) {
dd.device.notification.hidePreloader();
});
};
var ready = function () {
dd.runtime.permission.requestAuthCode({
corpId: '公司corpId',
onSuccess: function (result) {
result.code && signIn(result.code);
},
onFail: function (err) {
}
});
};
if (dd.env.platform === 'notInDingTalk') {
problem('请在钉钉内打开该应用');
} else {
dd.ready(ready);
dd.error(function (error) {
alert('dd error: ' + JSON.stringify(error));
});
}
// 点击页面中登录按钮,设置登录状态
// PC端轮询获得登录状态为
var setSignState = function () {
dd.device.notification.showPreloader({
text: '正在加载中..',
showIcon: true
});
this.$axios
.get('设置登录接口', { params: { signId: signId, userid: userId } })
.then(function(result) {
d.device.notification.hidePreloader();
alert(result.msg || '登录成功!');
dd.biz.navigation.close();
})
.catch(function(err) {
dd.device.notification.hidePreloader();
});
};
更新
测试后发现了一些问题:
Q:登录超时,浏览器刷新,依然弹出重新登录二维码,实际需要跳转到登录页。
A:增加判断条件,浏览器加载会重置该条件,从而判断跳转与弹出。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。