初识钉钉第三方H5应用开发

公司应用钉钉来进行日常管理也有些时日了,因为是技术部门,主要也就考勤,公司的事务上流程的走转还有项目的汇报上比之前更加规范了一些,领导指望着钉钉能有着更大的作用,于是把眼光放在了钉钉的第三方接入上,这篇文章就通过下面的内容带大家对于钉钉的认证接入和用户信息获取有一个初步的了解。

钉钉的第三方应用前端主要使用了两种,一种是H5,另一种是阿里自定义的微应用,它有着自己的规范。因为刚开始实践不想在这个方面花费太多精力,所以直接使用H5。

权限验证流程

先来看一张图,这是官方给出的用于权限验证的流程原理图。

首先基本的是需要注册一个企业并且作为企业的管理员从钉钉的管理后台获取CorpID和CorpSercret两个参数,其中第二个参数尤为重要,它是一个企业的最机密的数据。

通过这两个参数向接口请求获取token,这个token的有效期是两个小时,所以届时需要在服务器中缓存处理。

接着通过这个token再次向钉钉服务器请求获取ticket,这个ticket同样是2个小时的有效期。

继续使用前面一步的ticket,加上随机8位字符,以及时间戳还有请求url进行加密获取签名signature。这样就到了倒数第三步,钉钉的前端js会将上面总共5个参数进行计算获取得到一个CODE,这个code就可以向钉钉服务器获取用户信息了。

基本流程就是这样,下面通过将上述重现一下。

服务端实现 

注:1.钉钉提供了服务端的SDK,本文使用C#作为演示。

注:2.本文中的缓存系统使用redis,读者可自行使用其他缓存技术。

获取token

private string GetAccessToken()
{
    DNTCache cache = DNTCache.GetCacheService();
    string re_s = cache.RetrieveObject(CacheKeys.dingding_access_token) as string;
    if (Utils.StrIsNullOrEmpty(re_s))
    {
        IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.Corpid = CorpID;
        request.Corpsecret = CorpSecret;
        request.SetHttpMethod("GET");
        OapiGettokenResponse response = client.Execute(request);
        if (response.Errcode == 0)
        {
            cache.AddObject(CacheKeys.dingding_access_token, response.AccessToken, 7200);
            return response.AccessToken;
        }
        else
        {
            return string.Empty;
        }
    }
    else {
        return re_s;
    }
}

首先从redis中通过key获取token,如果获取到则反出,否则向钉钉服务器发出GET请求,参数就是CorpID和CorpSecret,这里HTTP请求的构建以及返回数据的解析SDK都已经封装好了:稍微说明,构建好IDingTalkClient这个对象,再新建OapiGettokenRequest请求,向里面填充参数,就可以了。

获取ticket

ticket的代码和token如出一辙:

IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/get_jsapi_ticket");
OapiGetJsapiTicketRequest request = new OapiGetJsapiTicketRequest();
request.AddOtherParameter("access_token", token);
request.SetHttpMethod("GET");
OapiGetJsapiTicketResponse response = client.Execute(request);
if (response.Errcode == 0)
{
    cache.AddObject(CacheKeys.dingding_js_ticket, response.Ticket, 7200);
    return response.Ticket;
}
else
{
    return string.Empty;
}

JS获取签名

服务端到此已经可以算完成一大半了。下面就是js的工作,假设新建的H5应用页面叫index.html。在这个页面引入钉钉的js包和jquery:

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcdn.staticfile.org%2Fjquery%2F3.2.1%2Fjquery.min.js%22%20charset%3D%22utf-8%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fg.alicdn.com%2Fdingding%2Fdingtalk-jsapi%2F2.0.8%2Fdingtalk.open.js%22%20charset%3D%22utf-8%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />

在页面加载的时候向后端请求获取本url的签名,就是一个简单的ajax请求,前端代码不在此赘述,回到后端,我们看一下签名算法:

public void OAuth(string href)
{
    string nonceStr = DingTalkSignatureUtil.GetRandomStr(8);
    string timestamp = GetTimestamp().ToString();
    string url = href.Trim().ToString();
    string accessToken = GetAccessToken();
    string jsApiTicket = GetTicket(accessToken);

    string string1 = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsApiTicket, nonceStr, timestamp, url);

    string signature = FormsAuthentication.HashPasswordForStoringInConfigFile(string1, "SHA1").ToLower();

    IDictionary<String, String> ps = new Dictionary<String, String>();
    ps.Add("nonceStr", nonceStr);
    ps.Add("timeStamp", timestamp);
    ps.Add("corpId", CorpID);
    ps.Add("signature", signature);

    rejsonp(JsonManage.basicJson("1", "", "", JsonConvert.SerializeObject(ps), "", true));

}

提醒下各位:1)url是不带参数的,也不带任何#后面的数据  2)时间戳是以1970年1月1日到现在的秒数

算法比较简单,将4个参数按照顺序排列后使用SHA-1算法计算出signature即可。

计算完毕后返回前端,前端的钉钉js包会再次计算并对比结果。

附上一段js请求成功的处理:

response=response.data
const config = {
agentId: response.agentId || '',
corpId: response.corpId || '',
timeStamp: response.timeStamp || '',
nonceStr: response.nonceStr || '',
signature: response.signature || '',
jsApiList: jsApiList || []
};
dd.config(config);

至此为止校验结束,可以向钉钉服务器请求获取用户数据了,在此之前还要通过钉钉的js包获取令牌用于免登录:

function authCode(corpId){
    return new Promise(function(resolve, reject){
        dd.ready(function(){
            dd.runtime.permission.requestAuthCode({
                corpId: corpId,
                onSuccess: function(result) {
                    resolve(result);
                },
                onFail : function(err) {
                    reject(err);
                }
            });
        });
    });
}

这里面reuslt.code就是免登录码

获取用户数据

分为两步,使用免登录码获取用户ID,使用用户ID获取用户完整信息:

public void Getuser(string code)
{
    IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getuserinfo");
    OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
    request.Code = code;
    request.SetHttpMethod("GET");

    OapiUserGetuserinfoResponse response = client.Execute(request, GetAccessToken());
    rejsonp(JsonManage.basicJson("1", "", "", JsonConvert.SerializeObject(response), "", true));
}

public void Getuserinfo(string Userid)
{
    IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get");
    OapiUserGetRequest request = new OapiUserGetRequest();
    request.Userid = Userid;
    request.SetHttpMethod("GET");
    OapiUserGetResponse response = client.Execute(request, GetAccessToken());
    rejsonp(JsonManage.basicJson("1", "", "", JsonConvert.SerializeObject(response), "", true));
}

第一个方法用的response就包含userid。

这两个请求有一个坑提醒下大家:请求不仅仅需要code和userid,每次请求还需要将token附上,并且不是在构建resquest的时候加上,而是发送请求的时候加上的,就是excute那个方法。

最后给大家看下获取到的完整的用户信息:

后面的交互逻辑就可以根据这个流程重复模拟就可以了,通过从钉钉获取到的数据进行业务的编写。

以上!

版权所属,如需转载,请注明出处:搜闲鱼

2,703 次浏览

发表评论

电子邮件地址不会被公开。 必填项已用*标注