钉钉端H5企业应用免登陆 根据前端传回的auth_code获取当前用户的userId等信息

最近我想在钉钉端创建一个H5应用,点击这个应用图标,获取当前钉钉登录用户个人信息,然后利用获取到的信息做后续的一些处理,如获取当前钉钉用户名下的订单信息诸如此类。此文将梳理从钉钉应用的创建到当前钉钉登录用户身份信息获取的整个过程。需要注意的是,这个办法比较适用于一个独立的应用免登陆。


在这里插入图片描述



1 创建应用

进入钉钉开发者后台。在此之前你必须是你企业的钉钉开发者或管理员,否则你没有创建钉钉端应用的权限。然后创建一个企业应用

2 OAuth登录授权

可以按照钉钉官方的教程走。
需要注意的是,你跟着教程走到步骤二的时候,官方教程会让你构造登录授权页面。这个页面是通过一个URL得到的,就是下面这个:
在这里插入图片描述
URL中的参数官方文档中也有详细说明,在此不做过多赘述。
这步走完之后你得到了一个URL,访问这个URL你就能看到钉钉的登录界面。

3 配置应用

进入你第一步创建的那个应用,然后进入到下面这个页面:
在这里插入图片描述

  • 点击开发管理,把你的项目所在服务器的公网地址填进去,注意必须是公网地址。有的时候你还需要将你公司的服务器出口地址加入,否则可能获取不到你想要的数据。
  • 应用首页地址和PC端首页地址,填你第二步构造好的URL
  • 后台管理地址如果没有可以先随便填个。
    这些做完,你在钉钉中点击你的应用,就能看到钉钉端的授权登录页面了。

4 后端获取第三步从前端传过来的auth_code参数

后端我用的是Django框架,所以这个参数我直接在视图函数中便获取到了:

def get_auth_code(request):
    """
    获取前端auth_code
    需要注意的是 这个视图函数就是第3步配置应用时 重定向url调用的视图函数
    """
    # GET 成功获取
    if request.method == 'GET':
        # 获取authCode
        authCode = request.GET.get('authCode')
        
        # 给这个auth_code设置一个session方便后面使用
        request.session['authCode'] = authCode
        request.session.set_expiry(7200)
        
        # 重定向到首页地址
        return redirect('/external/sale_support_client_index')

    # 非法HTTP请求
    else:
        return render(
            request,
            'external/client/sale_support_error_page.html',
            {'msg': "前端获取auth_code校验码失败"}
        )
    pass

5 定义调用钉钉端接口的方法

5.1 定义获取企业内部应用的access_token的方法

此接口钉钉官方文档

# 方法 获取钉钉端服务端接口的授权凭证access_token
def getServerAccessToken():
    """
    获取access_token服务端接口的授权凭证
    success: 返回access_token 注意这个返回值有2小时的过期时间 使用时应设置缓存
    fail: 打印提示信息
    """
    access_token = requests.get(
        url='https://oapi.dingtalk.com/gettoken',
        params={
            'appkey': 'xxxxxx',  # 应用信息中的AppKey
            'appsecret': 'xxxxxxxxxxxxxxxxxxxxxx'  # 应用信息中的AppSecret
        }
    )

    try:
        a_c = access_token.json()['access_token']
    except Exception as e:
        print("Out: --销售支持 获取access_token服务端接口的授权凭证 获取失败--")
        print("\t:", e)
    else:
        return a_c

5.2 定义获取用户身份信息的类

此对象有两个入参, 一个是第4步从前端获取到的auth_code;第二个是5.1获取到的access_token

# 钉钉端接口封装
class DingTalk:
    """钉钉端获取 userid"""
    def __init__(self, auth_code, server_access_token):
        self.auth_code = auth_code
        self.server_access_token = server_access_token

    def getUserAccessToken(self):
        """
        获取用户身份令牌
        """
        refresh_token_res = requests.post(
            url='https://oapi.dingtalk.com/v1.0/oauth2/userAccessToken',
            headers={
                'Host': 'api.dingtalk.com',
                'Content-Type': 'application/json',
                'x-acs-dingtalk-access-token': self.server_access_token
            },
            data=json.dumps({
                'clientId': 'xxxxxx',  # 应用信息中的AppKey
                'clientSecret': 'xxxxxxxxxxxxxxxxxxxxxxx',  # 应用信息中的AppSecret
                'code': self.auth_code,
                'grantType': 'authorization_code',  # 固定值authorization_code

            })
        )

        try:
            r_t_r = refresh_token_res.json()['accessToken']
        except Exception as e:
            print("Out: --销售支持 获取获取用户身份令牌access_token 获取失败--")
            print("\t:", e, refresh_token_res.json())
        else:
            return r_t_r

    def getUserUnionId(self):
        """
        获取用户unionId 此id可用于获取当前登录用户的userId
        """
        current_user_info = requests.get(
            url='https://oapi.dingtalk.com/v1.0/contact/users/me',
            headers={
                'Host': 'api.dingtalk.com',
                'Content-Type': 'application/json',
                'x-acs-dingtalk-access-token': self.getUserAccessToken()  # 用户身份令牌
            }
        )

        try:
            unionId = current_user_info.json()['unionId']
        except Exception as e:
            print("Out: --销售支持 获取用户unionId 获取失败--")
            print("\t:", e, current_user_info.json())
        else:
            return unionId

    def getUserId(self):
        """
        获取用户userId 此id是钉钉用户唯一身份标识
        """
        user_user_id = requests.post(
            url='https://oapi.dingtalk.com/topapi/user/getbyunionid',

            data={
                'unionid': self.getUserUnionId(),  # 当前用户unionId
                'access_token': self.server_access_token,  # 服务器接口凭证
            }

        )

        try:
            userid = user_user_id.json()['result']['userid']
        except Exception as e:
            print("Out: --销售支持 获取用户userid 获取失败--")
            print("\t:", e, user_user_id.json())
        else:
            return userid

总结

上述过程只是实际开发中遇到的并根据钉钉官方文档总结出来的一些经验,不排除有更好的办法,如果有,望不吝指点。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐