釘釘掃碼登陸成功禁止跳轉刷新

釘釘掃碼登陸第三方網站官方文檔索引:釘釘開放平臺 → (任意類型應用)→ 服務端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();
        });
};
相關文章
相關標籤/搜索