钉钉扫码登陆成功禁止跳转刷新

钉钉扫码登陆第三方网站官方文档索引:钉钉开放平台 → (任意类型应用)→ 服务端API → 身份验证 → 扫码登陆第三方网站,文档中详细的介绍了钉钉扫码登陆功能的实现。javascript

出现需求

因为表单复杂,用户编辑时间过长,提交表单提示token过时失效,须要从新扫码登陆,然而用户不但愿跳到登陆页,更不但愿从新编辑表单。css

一、token失效,在当前页面弹出登陆二维码。html

二、若是原用户扫码登陆成功可继续编辑表单。java

三、若是非原用户扫码登录成功则更新权限与功能并跳转首页。ios

解决需求

官方扫码登陆后须要页面跳转来传递 loginTmpCode 值,因此不能使用扫码登陆第三方网站功能登陆,须要自定义扫码登陆功能。web

开发前准备:axios

一、应用开发 → 建立H5微应用:免登鉴权。c#

二、登陆接口:鉴权后获取用户信息。api

三、H5微应用页面:钉钉端鉴权与登陆功能。session

四、发起登陆的接口:用于发起一个登陆,返回登陆id。

五、获取登陆的接口:用于轮询获取登陆状态,返回指定id的登陆的状态与信息。

六、设置登陆状态接口:设置用户登陆状态与信息。

七、安装 qrcode 模块:用来生成登陆二维码。

上菜

如下为实际项目的实现,代码有所调整。

一、判断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);
});

二、经过生成登陆的接口建立登陆,得到登陆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;
                }
            }
        }
    }
}

三、钉钉扫码后访问微应用,接收登陆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();
        });
};
相关文章
相关标签/搜索