管理员身份登录钉钉管理后台 https://oa.dingtalk.com/#/logins

创建一个钉钉H5微应用

H5微应用创建步骤和配置

点击前往钉钉开放平台 获取并记录【CorpId】

获取并记录CorpId

选择 应用开发》》》企业内部开发》》》H5微应用》》》创建应用

创建应用

创建H5微应用

记录应用凭证 【AgentId】【AppKey】【AppSecret】

应用凭证

填写开发管理应用首页地址和服务器出口IP

填写

根据需求添加接口权限

权限管理

发布应用和配置可见权限

发布应用和配置可见权限

至此我们已经可以在手机或PC的钉钉中使用自建应用了

钉钉


编写工具类

DingUtils工具类中的【agentid】=上述的【AgentId】/【appkey】=上述的【AppKey】/【appsecret】=上述的【AppSecret】/

AccessTokenD

/**
 * 钉钉AccessToken
 * @author Lehman
 * @Date 2021-04-08
 * @email 280668200@qq.com
 *
 */
@Data
public class AccessTokenD {

    /**
     * 生成的access_token。
     */
    private String access_token;

    /**
     * access_token的过期时间,单位秒。
     */
    private double expires_in;

    /**
     *     返回码描述。
     */
    private String errmsg;

    /**
     * 返回码。
     */
    private double errcode;

}

DingUser


/**
 * 钉钉user
 * @author Lehman
 * @Date 2021-04-08
 * @email 280668200@qq.com
 *
 */
@Data
public class DingUser {
    
    
    private String request_id;
    
    private int errcode;
    
    private String errmsg;
    
    private HashMap result;


}

Sns

/**
 * 钉钉Sns
 * @author Lehman
 * @Date 2021-04-08
 * @email 280668200@qq.com
 *
 */
@Data
public class Sns {
    
    private String unionid;
    
    private String openid;
    
    private String persistent_code;
    
    private String errmsg;
    
    private double errcode;

}

SendMsg

/**
 * 钉钉msg
 * @author Lehman
 * @Date 2021-04-08
 * @email 280668200@qq.com
 *
 */
@Data
public class SendMsg {

    /**
     * 请求ID
     */
    private String request_id;
    
    private String errmsg;
    
    private double errcode;
    
    private double task_id;
    
}

DingUtils

package com.windseeker.common.system.utlis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.gson.Gson;
import com.windseeker.common.core.utils.HttpsUtils;
import com.windseeker.common.system.entity.AccessTokenD;
import com.windseeker.common.system.entity.DingUser;
import com.windseeker.common.system.entity.SendMsg;
import com.windseeker.common.system.entity.Sns;
import org.apache.http.client.ClientProtocolException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * 钉钉工具类
 * @author Lehman
 * @Date 2021-04-05
 * @email 280668200@qq.com
 *
 */
@Configuration
public class DingUtils {



    private static String ding_agentid;
    private static String ding_appkey;
    private static String ding_appsecret;


    public  String getDing_agentid() {
        return ding_agentid;
    }
    @Value("${ding.agentid}")
    public  void setDing_agentid(String ding_agentid) {
        DingUtils.ding_agentid = ding_agentid;
    }

    public  String getDing_appkey() {
        return ding_appkey;
    }
    @Value("${ding.appkey}")
    public  void setDing_appkey(String ding_appkey) {
        DingUtils.ding_appkey = ding_appkey;
    }

    public  String getDing_appsecret() {
        return ding_appsecret;
    }
    @Value("${ding.appsecret}")
    public  void setDing_appsecret(String ding_appsecret) {
        DingUtils.ding_appsecret = ding_appsecret;
    }

    /**
     * 获取AccessToken
     * @return
     */
    public static AccessTokenD getAccessToken() {
        
        String access_token="";
        try {
             access_token= HttpsUtils.sendSSL("https://oapi.dingtalk.com/gettoken?appkey="+ding_appkey+"&appsecret="+ding_appsecret);
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        AccessTokenD accessToken=JSONArray.parseObject(access_token, AccessTokenD.class);
        return accessToken;
    }
    


    
    /**
     * 获取钉钉 DingUser
     * @return
     */
    public static DingUser getUser(String code) {

         String snsResult="";
         Gson gson=new Gson();
         Map<Object, Object> src = new HashMap<Object, Object>();
         src.put("code",code);
        try {
            snsResult = HttpsUtils.sendPost("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token="+getAppToken(),gson.toJson(src));
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        DingUser dingUser=JSONArray.parseObject(snsResult, DingUser.class);
        return dingUser;
    }
    
    
    /**
     * 钉钉推送发送消息到用户
     * @param userIDList
     * @param msgJson
     * @return
     */
    public static SendMsg sendMsgToUser(String userIDList, String msgJson) {
         String sendResult="";
         Gson gson=new Gson();
         Map<Object, Object> src = new HashMap<Object, Object>();
         src.put("agent_id",ding_agentid);
         src.put("userid_list",userIDList);
         Map<String, String> markdown=new HashMap<String, String>();
         markdown.put("title", "待处理");
         markdown.put("text", msgJson);
         Map<String, Object> msg=new HashMap<String, Object>();
         msg.put("msgtype", "markdown");
         msg.put("markdown", markdown);
         src.put("msg",JSON.toJSON(msg));
        try {
            sendResult = HttpsUtils.sendPost("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="+getAppToken(),gson.toJson(src));
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SendMsg sendMsg=JSONArray.parseObject(sendResult, SendMsg.class);
        return sendMsg;
    }
    
    
    /**
     * 应用获取Token 
     * @return
     */
    public static String getAppToken() {
        String token="";
        try {

            String access_token= HttpsUtils.sendSSL("https://oapi.dingtalk.com/gettoken?appkey="+ding_appkey+"&appsecret="+ding_appsecret);
            AccessTokenD accessToken=JSONArray.parseObject(access_token, AccessTokenD.class);
            token=accessToken.getAccess_token();
        }catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return token;
    }
    
    

}


H5微应用自动授权登录

根据前面的工具类和【AgentId】 【AppKey】【AppSecret】【CorpId】可以自定义编写业务需求,最终实现前端/后端互通(此处根据自己业务实现,此处不在赘述)

基础思路如下:

浏览器引入

<script src="https://g.alicdn.com/dingding/dingtalk-jsapi/2.13.42/dingtalk.open.js"></script>

前端处理

dd.ready(function() {
    dd.runtime.permission.requestAuthCode({
            corpId: "ding12345xxx", // 企业id
            onSuccess: function (info) {
            let code = info.code // 通过该免登授权码可以获取用户身份  
                //钉钉自动登录
                $.ajax({
                    url: requestUrl+'login',
                    type: 'POST',
                    data:{code:code}, //    授权码,有效期5分钟,且只能使用一次,使用后会失效。
                success: function (res,status,xhr) {
                    if (0 === res.code) {
                        layer.msg('登录成功', {icon: 1, time: 1000, shade: [0.3,'#000']})
                    } else {
                        layer.msg(res.msg || '登录失败', {icon: 2, anim: 6})
                    }
                },error:function (e) {
                    layer.msg(`企业微信自动登录接口异常`)
                    return;
                }
              });
    }});
});


后端处理

String code = request.getParameter("code");
if (StringUtils.isBlank(code)) {
    return JsonResult.error("钉钉接口异常,获取code失败或code失效!");
} else {
    AccessTokenD accessToken = DingUtils.getAccessToken();

    if (accessToken == null || accessToken.getErrcode() != 0) {
        return JsonResult.error("钉钉接口异常,获取access_token失败," + accessToken.getErrmsg() + "!");
    } else {
        DingUser dingUser = DingUtils.getUser(code);
        if (dingUser == null || dingUser.getErrcode() != 0) {
            return JsonResult.error("钉钉接口异常,获取userid失败," + dingUser.getErrmsg());
        } else {
            String dingUserId = dingUser.getResult().get("userid").toString();
            // .... 此处根据业务需求编写代码 其中【dingUserId】为用户钉钉标识!!!

            if (【登录业务返回结果】)
              return JsonResult.ok("登录成功!");
            else
              return JsonResult.error("您的钉钉账号当前未与系统绑定,请使用账号密码登录!");
        }
    }
}


web应用扫码登录钉钉

接入应用

填写接入的信息

填写接入的信息

记录appld和appSecret

记录appld和appSecret

tips:根据文档编写前后端代码,实现扫码登录

扫码登录

步骤一:在页面中先引入如下JS文件(支持HTTPS)

<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>

步骤二:在需要使用钉钉登录的地方实例以下JS对象

/*
 * 解释一下goto参数,参考以下例子:
 * var url = encodeURIComponent('http://localhost.me/index.php?test=1&aa=2');
 * var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=SuiteKey&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+url)
 */
var appid='XXXXXXXX';   //SuiteKey/SuiteSecret(第三方企业应用)或AppKey/AppSecret(企业内部应用)
var redirect_uri= encodeURIComponent('微应用回调的URL/loginDing(自定义接口)');
var ding_goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid='+appid+'&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+redirect_uri)
var obj = DDLogin({
        id:"ding_login",//这里需要你在自己的页面定义一个HTML标签并设置id
        goto: ding_goto, //请参考注释里的方式
        style: "border:none;background-color:#FFFFFF;",
        width : "365",
        height: "400"
 });

用户允许授权后,将会重定向到redirect_uri的网址上,并且带上【code】参数

步骤三:编写【重定向地址】接口

上述重定向到接口后,地址会带上【code】和【state】参数,我们根据【code】和【state】参数以及上述的【DingUtils】编写业务代码 实现扫码登录(此处根据自己业务实现,下述代码为大概思路)

/**
 * 钉钉扫码登录
 * @param code
 * @return
 */
@RequestMapping("/loginDing")
@ResponseBody
public JsonResult login(String code,String state) {
    if (StringUtil.isBlank(code)) {
        return  JsonResult.error("Error code:280450---钉钉接口异常,获取code失败或code失效!");
    } else {
        AccessToken accessToken = DingUtils.getAccessToken();

        if (accessToken == null || accessToken.getErrcode() != 0) {
            return  JsonResult.error("Error code:280450---钉钉接口异常,获取access_token失败,错误信息:" + accessToken.getErrmsg() + "!");
        } else {
            Sns sns = DingUtils.getSns(accessToken.getAccess_token(), code);

            if (sns == null || sns.getErrcode() != 0) {
                return  JsonResult.error("Error code:280450---钉钉接口异常,获取Unionid失败,错误信息:" + sns.getErrmsg() + "!");
            } else {
                DingUser dingUser = DingUtils.getUser(accessToken.getAccess_token(), sns.getUnionid());
                if (dingUser == null || dingUser.getErrcode() != 0) {
                    return  JsonResult.error("Error code:280450---钉钉接口异常,获取userid失败," + dingUser.getErrmsg());
                } else {
                    String dingUserId = dingUser.getResult().get("userid").toString();
                    // .... 此处根据业务需求编写代码 其中【dingUserId】为用户钉钉标识!!!
                    if (【登录业务返回结果】) {
                        return JsonResult.ok("登录成功!");
                    } else {
                        return  JsonResult.error("Error code:280404---您的钉钉账号当前未与系统绑定,请使用账号密码登录!");
                    }
                }
            }
        }
    }
}


开发使用文档

无论是web接入,还是微应用的配置,在配置完毕后具体使用请结合钉钉开发文档食用https://developers.dingtalk.com/document/app/document-upgrade-notice

Last modification:August 24, 2023
如果觉得我的文章对你有用,您可以给博主买一杯果汁,谢谢!