美文网首页Angular框架交流
Angular开发钉钉微应用

Angular开发钉钉微应用

作者: 是小太阳呀 | 来源:发表于2020-04-14 15:32 被阅读0次

    前端:Angular5.2

    后端: 用dgate模拟后端返回数据。(业务需要)

    Github地址:https://github.com/DTeam-Top/dgate/blob/master/docs/user_guide.md

    创建钉钉微应用及其免登流程请查看钉钉官方文档。

    微应用https://oa.dingtalk.com/index.htm#/microApp/microAppList

    免登:https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.T3ohnj&treeId=168&articleId=107551&docType=1

    一. 准备工作

    将dingtalk.js集成到angular5中

    1. 下载dingtalk.js 放到src目录下。(见钉钉官网)

    2. 在src目录下新建dingtalk.d.ts文件,并声明变量dd以便调用jsapi。

    declare var dd: any;
    

    3. 在angular-cli.json文件中“scripts”中添加:

     "scripts": [
            "dingtalk.js",
            ...
          ],
    

    4. 在tsconfig.json文件中添加:

     "types": ["dingtalk.d.ts"],
    

    dingtalk.js集成完毕。

    配置环境

    1. 在environment.ts以及dgate中配置好自己的ip。

    2. 为了让手机访问angular项目需要开启ip访问,可以启动的时候:

     ng serve --host 0.0.0.0
    

    也可以在package.json中更改“scripts”对应“start”的配置。

    1. 新建dingding.ts文件,存放微应用的corpId,secret,agentId以便后面直接读取。

    2. 请将手机和电脑位于同一局域网中。

    用户数据准备

    本地创建一个mock-user.ts文件,以便存放用户信息。主要用于登录,存放用户名,密码,以及dd_userid即可。(dd_userid为通过dd获取到的userid,初始为空。)

    二. 项目思路

    用户通过钉钉手机端访问自己创建的微应用。首次登录时通过用户名密码登录,然后记录该用户的userid。下次登录时匹配该userid即可。

    dingding-backend.service.ts模拟实际项目中后端请求钉钉接口。

    dingding-web.service.ts模拟实际项目中前端使用钉钉jsapi。

    三. 实现

    1. 获取access_token:https://oapi.dingtalk.com

    /gettoken?corpid=id&corpsecret=secrect (后端)

    1. 根据access_token获取ticket:https://oapi.dingtalk.com

    /get_jsapi_ticket?access_token=ACCESS_TOKE(后端)

    1. 根据ticket获取签名signature鉴权(后端)

    根据官网上https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7386797.0.0.Sfinbc&source=search&treeId=168&articleId=107551&docType=1#s6 计算。

    image.png
    image.png

    在angular5中签名算法代码如下:

    getSign(access_token,ticket:string) {
            // signature, nonstr, url, timestamp, CorpId, agentId
            var origUrl = decodeURIComponent(window.location.href);
            var origUrlObj =  url.parse(origUrl);
            delete origUrlObj['hash'];
            var newUrl = url.format(origUrlObj);
    
            var nonceStr = 'abcdefg';
            var timeStamp = new Date().getTime();
            var ticket = ticket;
            var plain = 'jsapi_ticket=' + ticket +
                        '&noncestr=' + nonceStr +
                        '&timestamp=' + timeStamp +
                        '&url=' + newUrl;
    
            var sha1 = CryptoJS.SHA1(plain);
            var signature = sha1.toString(CryptoJS.enc.hax)
    
            let config = {
                accessToken:access_token,
                signature: signature,
                nonceStr: nonceStr,
                timeStamp: timeStamp,
                corpId: dingding.corpId,
                agentId: dingding.agentId
            };
            this.dingding.emit({type: 'config', config: config});
        }
    

    其中用到了CryptoJs使用SHA1加密,具体请参考官方文档。

    然后通过EventEmitter模拟将config发送到“前端”。

    1. dingding-web-service.ts获取到condig后,通过JSAPI获取免登code。
     ddJSAPI(config){
            const $this = this;
            dd.config({
                       agentId: config.agentId,
                       corpId: config.corpId,
                       timeStamp: config.timeStamp,
                       nonceStr: config.nonceStr,
                       signature: config.signature,
                       jsApiList: ['device.notification.confirm',
                         'device.notification.alert',
                         'device.notification.prompt',
                         'biz.chat.chooseConversation',
                         'biz.ding.post','biz.user.get']
                     });
                  
                    dd.ready(function() {
                       dd.runtime.permission.requestAuthCode({
                         corpId: dingding.corpId,
                         onSuccess: function(result) {
                           $this.dingding.emit({type: 'code', code:result.code});
                         },
                         onFail : function(err) {}
                     });
                    //  dd.biz.user.get({
                    //     corpId:"dingbb55d760782ca6d535c2f4657eb6378f",
                    //     onSuccess: function (info) {
                    //     console.log('======.info===');
                    //     console.log(info);
                    //     alert(JSON.stringify(info))
                    //   },
                    //   onFail: function (err) {}
                    // });
                   })
        }
    

    获取到免登code后传递给“后端”。

    可以通过dd.biz.user.get获取用户信息,为了安全起见,官方推荐将code传给后台,由后端来获取用户信息。

    1. 后端通过免登code获取用户info

    获取info:https://oapi.dingtalk.com

    /user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE

    返回:


    image.png
    1. 通过userid获取详细信息(非必要)

    获取详细信息:https://oapi.dingtalk.com

    /user/get?access_token=ACCESS_TOKEN&userid=zhangsan

    1. 获取到userid后即可结合用户名密码进行绑定。

    下次该用户访问时即可通过userid确定身份。

    调试:

    1. 下载钉钉开发版,将手机通过usb连接电脑,打开usb调试。

    钉钉开发版以及配置:https://open-doc.dingtalk.com/docs/doc.htm?treeId=171&articleId=104908&docType=1

    1. 打开chrome,输入chrome://inspect/#devices 进入调试页面。

    2. 进入微应用。这个时候会出现一个错误:


      image.png

    vendor.bundle.js文件太大。所以启动的时候还需要加上--aot

    1. 现在应该可以正常访问微应用了,但是请求钉钉接口的时候,会报错:


      image.png

    angular解决跨域的问题是设置反向代理。

    (1)在项目下添加proxy.config.json文件(和package.json同级)

    (2)添加文件内容:

    {
    
        "/gettoken":{
    
        "target": "https://oapi.dingtalk.com",
    
        "secure": "false",
    
        "changeOrigin": true
    
        },
    
       "/get_jsapi_ticket":{
    
        "target": "https://oapi.dingtalk.com",
    
        "secure": "false",
    
        "changeOrigin": true
    
        },
    
       
        "/user":{
    
        "target": "https://oapi.dingtalk.com",
    
        "secure": "false",
    
        "changeOrigin": true
    
        }
    }
    

    (3)修改请求:

    由于设置了反向代理,所以请求为:

     this.http.get('/gettoken', {params}).subscribe((res:any)=>{
               this.access_token = res.access_token;
               this.getTicket(res.access_token);
            })
    

    启动时加上 --proxy-configproxy.config.json

    最终启动命令为:

     "start": "ng serve --host 0.0.0.0 --aot --proxy-config proxy.config.json",
    

    更多反向代理信息请查看Angular官方文档。

    1. 访问钉钉接口后获取到token等数据,但是发现页面并没有出现,chrome控制台报错:‘null’ is not a function

    通过排查发现是angular和android浏览器兼容问题。

    解决:

    将polyfills.ts文件中支持IE浏览器的特性打开:

    /** IE9, IE10 and IE11 requires all of the following polyfills. **/
    // import 'core-js/es6/symbol';
    import 'core-js/es6/object';
    import 'core-js/es6/function';
    import 'core-js/es6/parse-int';
    import 'core-js/es6/parse-float';
    import 'core-js/es6/number';
    import 'core-js/es6/math';
    import 'core-js/es6/string';
    import 'core-js/es6/date';
    import 'core-js/es6/array';
    import 'core-js/es6/regexp';
    import 'core-js/es6/map';
    import 'core-js/es6/weak-map';
    import 'core-js/es6/set';
    

    现在可以看到页面了。

    1. 免登流程完毕。但是发现angular从dgate获取的数据,

    不能主动渲染页面。

    解决:

    必须手动触发变更检测。

    1. 导入ChangeDetectorRef
    import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
    
    1. 构造中
     constructor(...
                , private _ref: ChangeDetectorRef) {
                  ...
                  this._ref.detach();
    
    1. 获取到数据后
     this._ref.detectChanges();
    

    更多变更检测信息请查看Angular官方文档。

    由于每个component都需要加上变更检测,所以如果项目中component相互之间的结构复杂,那么对项目性能有很大的影响。

    相关文章

      网友评论

        本文标题:Angular开发钉钉微应用

        本文链接:https://www.haomeiwen.com/subject/ijltvhtx.html