钉钉H5微应用免登

594 阅读3分钟

最近咱们部门没什么新的项目,所以手头上暂时没什么工作安排,于是乎想写一些技术文章锻炼自己的写作能力、以及对一些功能点的描述能力,(第一次编写,请大家多多包涵,有写错的或者感觉看不懂欢迎留言评论)因为我们开发部团队主要是做钉钉结合学校的教育类项目,所以这次为大家带来的是钉钉的前端免登业务逻辑,以及在免登时需要做的一些前置判断的相关逻辑,这些代码其实并不是我编写的,是我们部门的老罗写的,怀揣着程序员的热爱分享的精神,我决定先斩后奏,等我发了文章在和老罗说,哈哈哈哈

  1. 首先我们打开钉钉开发者平台H5微应用开发文档,在打开文档之后它就告诉我们第一项准备工作,是需要使用npm安装钉钉JSAPI包:

     npm install dingtalk-jsapi --save
    
  2. 钉钉应用免登需要获取企业的corpId ,并且分为企业内部应用和第三方应用

    • 企业内部应用:就是只供一个企业内部使用,所以只需要使用当前企业corpId即可

    • 第三方企业应用:是可以上架到钉钉应用市场,其他企业可以通过应用市场开通使用,所以每个企业的corpId不同,我们所获取corpId的方式也是不同,第三方企业获取corpId我们是在钉钉部署时需要在URL中使用$CORPID$做为参数占位符,钉钉容器会将$CORPID$替换为当前访问用户的企业corpId,例如,微应用首页地址为https://www.dingtalk.com,需要获取当前访问用户的企业corpId值,微应用首页地址可改为https://www.dingtalk.com?corpId=$CORPID$。

      image.png

  3. 了解了企业内部应用和第三方应用,接下来我们就开始来书写我们的钉钉免登,我们可以新建一个文件(ddUtils.js)来存放关于钉钉的功能函数,下面的是否内部应用、内部应用企业 ID我们是单独存放在一个文件的,这里为了方便就放在一个页面了, 你们自己做下分离

     module.exports = {
       /**
       * 是否内部应用
       */
       isInternalApplication:false,
       /**
       * 内部应用企业 ID
       */
       corpId: 'xxxxx',
     }
         
     import * as dd from 'dingtalk-jsapi'
     /**
     * 判断是否钉钉环境
     */
     export const isInDingTalk = () => {
        return dd.env.platform !== "notInDingTalk"
     }
     /**
     * 免登
     * @param { Function } callBack
     */
     export const noRegistration = ( callBack )=> {
       showLoading()
       if (isInDingTalk()) {
    	const corpId = isInternalApplication? corpId : uni.getStorageSync('corpId')
    	dd.ready(() => {
    		dd.runtime.permission.requestAuthCode({
    			corpId,
    			onSuccess: async ( info ) => {
    				hideLoading()
    				const { data:{data:{token}} } = await app_login(info.code , corpId )
    				uni.clearStorageSync()
    				uni.setStorageSync('token', token)
    				callBack && callBack() //再次进行调用
    			},
    			onFail: ( err ) => {
    				hideLoading()
    				alert(`onFail:${JSON.stringify(err)}${corpId}`);
    			}
    		})
    	})
      } else {
    	hideLoading()
    	alert('请在钉钉环境打开')
      }
    }
    
  4. 在我们封装的接口请求里,如果报401就会进行免登

    export const myRequest = ({ method,data,url,isLoading,callBack,timeout,responseType }) => {
            const upperMethod = method?.toLocaleUpperCase(),
                  contentType = upperMethod === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded';
            return new Promise((resolve, reject) => {
                    uni.request({
                            url: `${config.baseUrl}/${url}`,
                            method: upperMethod || 'GET',
                            header: {
                                    "Authorization": "Bearer " + uni.getStorageSync('token'),
                                    "Content-Type": contentType
                            },
                            data: data || {},
                            timeout: timeout || 10000,
                            responseType: responseType || 'text',
                            success(res) {
                                    const { data: {code,data,msg} } = res
                                    if (code === 401) { // token过期,或者没有token
                                            return noRegistration(callBack)
                                    }
                                    if (code !== 200) {
                                            if (code === 500) {return toast(!msg ? '服务器异常' : msg)}
                                            return toast(data?.message)
                                    }
                                    resolve(res)
                            },
                            fail(err) {
                                    if (err.errMsg != 'request:fail abort') { toast(err.errMsg) }
                                    reject(err)
                            },
                            complete() {
                                    isLoading && hideLoading()
                            }
                    })
            })
    }
    
    
  5. 我们就可以开始在我们应用所需要展示的第一个页面编写免登的一个代码和逻辑了

         created() {
                     uni.clearStorageSync(); // 这里每次先把本地的缓存清除一下
                     this.isInDingTalk = isInDingTalk()
               // 是否在钉钉环境
                     if (this.isInDingTalk) {  
                          // 企业内部应用
                          if (config.isInternalApplication) {
                                  this.getUserinfo()
                                  return
                          }
                          // 第三方企业应用
                          const corpId = /corpId=([^=&]*)/.exec(window.location.href)[1].slice(0, -2)
                          uni.setStorage({
                                  key: 'corpId',
                                  data: corpId,
                                  success: () => {
                                          this.getUserinfo()
                                  }
                          });
                     } else {
                          // this.getCode()
                     }
           },
          methods: {
                     // 加载用户信息
                     async getUserinfo() {
                          let {data: {data: userInfo}} = await getUserInfo(this.getUserinfo)
                    // 在进行第一次接口调用时,没有token,
                    // 在我们封装的请求那步就走401,会调用免登的函数,
                    // 这里我们还传进去了一个this.getUserinfo的callBack函数,
                    // 然后再钉钉免登函数那里获取到token之后,那里会进行一个callBack调用,
                    // 会在次调用this.getUserinfo
                     },
          }