python项目对接钉钉SDK的实现


Posted in Python onJuly 15, 2019

 钉钉SDK

对接sdk还是遇到不少问题的

钉钉python版SDK文档地址:https://dingtalk-sdk.readthedocs.io/zh_CN/latest/

钉钉官方服务端文档:https://open-doc.dingtalk.com/microapp/serverapi2

为了避免调试出现不必要的参数错误,前期钉钉配置要做好,血和泪的教训?

准备好下面几个参数

DINGTALK_CORP_ID = "重点:企业应用ID"
# 钉钉微应用
DINGTALK_APP_KEY = "微应用APP_KEY"
DINGTALK_CORP_SECRET = "微应用SERCRET"
# 钉钉移动应用(扫码登录),在移动应用接入菜单里配置
DINGTALK_APP_ID = "移动应用APP_ID"
DINGTALK_APP_SECRET = "移动应用APP_SECRET"
# 钉钉aes加密(随机)
DINGTALK_AES_TOKEN = "43位字符串 a-zA-Z0-9中生成"
DINGTALK_TOKEN = "字符串随便填"

一. 第三方web网站扫码登录1. 流程

钉钉扫码—>判断是否公司员工—>登录

python项目对接钉钉SDK的实现

python项目对接钉钉SDK的实现

关于web系统的两种接入方式,都只能获取到用户的钉钉身份,并不能获取到用户是否在企业中

解决方法:

批量同步钉钉人员信息到数据库,登录后匹配数据库,新进员工通过钉钉回调同步到数据库,回调未生效人工审核后手动更新数据库

由于钉钉开发文档读的不够仔细导致调试频繁出错,所以开发流程我简单说,把细节放大

前端导入钉钉scrpit文件开发扫码页面

<script src="//g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
<script>
var url="http://erp.vaiwan.com/api/v1.0/ding_test";
var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingoadwjj1iszubeh9rnf&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+url);
var obj = DDLogin({
   id:"login_container",
   goto: goto,
   style: "border:none;background-color:#FFFFFF;",
   width : "365",
   height: "400"
 });

var hanndleMessage = function (event) {
    var origin = event.origin;
    console.log("origin", event.origin);
  	//判断是否来自ddLogin扫码事件。
    if( origin == "https://login.dingtalk.com" ) {
      //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了
      var loginTmpCode = event.data;
      console.log("loginTmpCode", loginTmpCode);
      if(loginTmpCode){
        let uri="https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingoadwjj1iszubeh9rnf&response_type=code&scope=snsapi_login&state=STATE&redirect_uri="+url+"&loginTmpCode="+loginTmpCode;
        // 跳转
        location.href = uri;
      }
    }
};

if (typeof window.addEventListener != 'undefined') {
  window.addEventListener('message', hanndleMessage, false);
} else if (typeof window.attachEvent != 'undefined') {
  window.attachEvent('onmessage', hanndleMessage);
}
</script>

配置扫码后跳转页面(就是第一步goto参数里的url),钉钉会自动在跳转页面路由后添加codestate参数

python项目对接钉钉SDK的实现

拿到code请求后端接口

<script src="https://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script>
  // location.search: "?code=bb42ec66ed5...&state=STATE"
  let code = location.search.split("&")[0].split("=")[1];
  $.ajax({
    type:"post",
    url:'http://erp.vaiwan.com.cn/api/v1.0/getinfo',
    data:{
      "code":code
    },
    success:function(data){
      console.log(data)
    }
  })
</script>

后端用appid和appsecret获取access_token

import requests
from dingtalk.client import SecretClient

class GetInfoByCode(object):
  def __init__(self):
    self.url = "https://oapi.dingtalk.com/sns"

  def get_access_token(self):
    resp = requests.get(
      url=self.url + "/gettoken",
      params=dict(appid=DINGTALK_APP_ID, appsecret=DINGTALK_APP_SECRET)
    )
    resp = resp.json()
    return resp["access_token"]

用access_token和code获取用户unionid

def get_persistent_code(self, code, token):
    resp = requests.post(
      url="%s/get_persistent_code?access_token=%s" % (self.url, token),
      json=dict(tmp_auth_code=code),
    )
    resp = resp.json()
    return resp["unionid"]

用unionid换取userid

ding_client = SecretClient(corp_id=DINGTALK_CORP_ID,
               corp_secret=DINGTALK_CORP_SECRET)
# 这块提醒下一定要做缓存,由于我之前没做缓存,超过钉钉使用频率而被限制了,修改下上面那句代码
import redis
from dingtalk.storage.kvstorage import KvStorage

# redis做缓存
redis_ding = redis.StrictRedis(REDIS_HOST, REDIS_PORT, db=0)
# 划重点,因为我是第三方web网站,没有使用E应用,所以我的corp_id填的是微应用的id,而不是企业应用ID(corp_id)
ding_client = SecretClient(
  corp_id=DINGTALK_APP_KEY,
  corp_secret=DINGTALK_CORP_SECRET,
  storage=KvStorage(redis_ding))

userid = ding_client.user.get_userid_by_unionid(unionid)

userid换取user详情

user = ding_client.user.get(userid["userid"])

二. 加解密

应用场景: 钉钉回调

事件流程:注册回调事件—>处理事件内容(新增员工、更新部门等),返回钉钉加密json

python项目对接钉钉SDK的实现

就是说你调用注册事件API,钉钉会给你需要注册的url发送一个post请求,你得按要求返回success,否则注册失败

1.注册事件

python项目对接钉钉SDK的实现

再看看什么是success的加密json数据

python项目对接钉钉SDK的实现

如果你没有看懂的话,很巧 我也看不懂…

json数据包含这些参数

python项目对接钉钉SDK的实现

时间戳和nonce容易拿,问题在于encryptmsg_signature的生成

因为钉钉没有提供python的加解密库,所以看到这块我有点懵

python项目对接钉钉SDK的实现

钉钉的文档看不太懂…

python项目对接钉钉SDK的实现

百度搜了下 发现有人自己封装了这个库,我看了下名字XXXcryptocrypto这个单词好像在sdk里边见过。

看了sdk目录,果然,虽然钉钉sdk虽然没写关于加解密的内容,但是它其实已经封装了这个库

使用

from dingtalk.crypto import DingTalkCrypto

class Crypto(object):
  def __init__(self):
    # 随便填的字符串
    self.token = DINGTALK_TOKEN
    # 自己生成的43位随机字符串
    self.aes_key = DINGTALK_AES_TOKEN
    # 钉钉企业ID
    self.corpid = DINGTALK_APP_ID
    self.crypto = DingTalkCrypto(
      token=self.token,
      encoding_aes_key=self.aes_key,
      corpid_or_suitekey=self.corpid
    )

说明

原本是不需要自己封装的。看dingtalk的源码

python项目对接钉钉SDK的实现

在开始定义ding_client的时候,只需要填参数就可以,经过我反复的调试,发现因为我开发的是企业内部应用-微应用,而不是E应用,所以这里填的corp_id其实是微应用app_key,参数不正确导致后边调试一直返回文本非success错误,为了不与上边填的参数冲突,所以自己封装Crypto类,填写的corp_id是企业应用id

封装好Crypto这个类,就可以调用啦, 先测试返回给钉钉的结果是否正确

from ... import Crypto

class EventCallBack(Resource):
  def __init__(self):
    self.crypto = Crypto().crypto
    
  def post(self):
    # 返回加密success
    result = self.crypto.encrypt_message(
      msg="success",
      nonce="123456",
      timestamp=int(time.time()*1000)
    )
    return result

事情没这么容易结束…

这个post方法你需要对回调事件作出处理而不是仅仅返回success,所以最终需要这样, 对结果进行处理

def post(self):
    po = request.json["encrypt"]
    data = request.values
    # 返回加密success
    result = self.crypto.encrypt_message(
      msg="success",
      nonce="123456",
      timestamp=int(time.time()*1000)
    )
    # 获取到事件及其他信息
    callback = self.crypto.decrypt_encrypt_str(
      encrypt_str=po,
      nonce=data["nonce"],
      timestamp=data["timestamp"],
      signature=data["signature"]
    )
    # demjson可以把字符串转为字典,否则取值失败
    # 安装 pip install demjson
    callback = demjson.decode(callback)
    # 判断事件类型,作出相应回调
    if callback["EventType"] == "user_add_org":
      # 添加员工
      ...
    elif callback["EventType"] == "org_dept_create":
      # 添加部门
      ...
    return result

三. 调试

# 钉钉内网穿透工具,主要作用是方便本地调试需要回调域名的接口
# 地址: https://open-doc.dingtalk.com/microapp/debug/ucof2g
可以后台启动

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python脚本实现自动将数据库备份到 Dropbox
Feb 06 Python
Python编程实现粒子群算法(PSO)详解
Nov 13 Python
Django 连接sql server数据库的方法
Jun 30 Python
Python 实现文件打包、上传与校验的方法
Feb 13 Python
Django基础知识 URL路由系统详解
Jul 18 Python
Python数据可视化处理库PyEcharts柱状图,饼图,线性图,词云图常用实例详解
Feb 10 Python
Python sep参数使用方法详解
Feb 12 Python
python生成13位或16位时间戳以及反向解析时间戳的实例
Mar 03 Python
python except异常处理之后不退出,解决异常继续执行的实现
Apr 25 Python
Python 保存加载mat格式文件的示例代码
Aug 04 Python
Elasticsearch 聚合查询和排序
Apr 19 Python
Python 绘制多因子柱状图
May 11 Python
用Python识别人脸,人种等各种信息
Jul 15 #Python
django中账号密码验证登陆功能的实现方法
Jul 15 #Python
python tkinter窗口最大化的实现
Jul 15 #Python
在pycharm下设置自己的个性模版方法
Jul 15 #Python
Pycharm新建模板默认添加个人信息的实例
Jul 15 #Python
在python中将list分段并保存为array类型的方法
Jul 15 #Python
详解Python对JSON中的特殊类型进行Encoder
Jul 15 #Python
You might like
8个出色的WordPress SEO插件收集
2011/02/26 PHP
第五章 php数组操作
2011/12/30 PHP
php文件下载处理方法分析
2015/04/22 PHP
php readfile()修改文件上传大小设置
2017/08/11 PHP
Yii2框架配置文件(Application属性)与调试技巧实例分析
2019/05/27 PHP
不安全的常用的js写法
2009/09/15 Javascript
动态加载图片路径 保持JavaScript控件的相对独立性
2010/09/06 Javascript
jquery获取tr中控件值并操作tr实现思路
2013/03/27 Javascript
用jquery统计子菜单的条数示例代码
2013/10/18 Javascript
基于Jquery代码实现支持PC端手机端幻灯片代码
2015/11/17 Javascript
js倒计时简单实现方法
2015/12/17 Javascript
js实现瀑布流的三种方式比较
2020/06/28 Javascript
省市联动效果的简单实现代码(推荐)
2016/06/06 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
vue2中使用less简易教程
2018/03/27 Javascript
关于layui 弹出层一闪而过就消失的解决方法
2019/09/09 Javascript
jQuery实现推拉门效果
2020/10/19 jQuery
[01:00]DOTA2 store: Collection of Artisan's Wonders
2015/08/12 DOTA
pygame加载中文名mp3文件出现error
2017/03/31 Python
Python实现字典按照value进行排序的方法分析
2017/12/23 Python
Python多线程中阻塞(join)与锁(Lock)使用误区解析
2018/04/27 Python
Python使用itertools模块实现排列组合功能示例
2018/07/02 Python
python3.5绘制随机漫步图
2018/08/27 Python
python 多线程将大文件分开下载后在合并的实例
2018/11/09 Python
Python基于gevent实现高并发代码实例
2020/05/15 Python
python实现三种随机请求头方式
2021/01/05 Python
用HTML5制作视频拼图的教程
2015/05/13 HTML / CSS
Mixbook加拿大:照片书,照片卡,剪贴簿,年历和日历
2017/02/21 全球购物
英国豪华真皮和布艺沙发销售网站:Darlings of Chelsea
2018/01/05 全球购物
2013英文求职信模板范文
2013/11/15 职场文书
入股协议书
2014/04/14 职场文书
优秀党员先进事迹材料
2014/12/18 职场文书
党员承诺书范文2015
2015/04/27 职场文书
公安忠诚教育心得体会
2016/01/23 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
导游词之寿县报恩寺
2020/01/19 职场文书