钉钉获取公司内部架构之获取Access_Token

本文详细介绍了使用钉钉SDK进行应用开发的步骤,包括下载SDK、获取企业CorpId和CorpSecret,以及如何通过PHP框架Laravel获取并更新Access Token。

 

1.开发前准备:(首先你要是开发者才可以哦

sdk下载链接:https://open-doc.dingtalk.com/microapp/serverapi2/vzzrkv

详见钉钉开发文档:

https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.1ec24a97jgIF1p&treeId=371&articleId=106816&docType=1

2.获取企业的CorpId 和 CorpSecret

具体获取方式见文档:

https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.27e24a97wTFhm3&treeId=371&articleId=106926&docType=1

 

3.获取Access_Token

 

详见:

https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.be384a97wkguO9&treeId=371&articleId=104980&docType=1

我用的是laravel框架(无论什么框架写之前下载好的引入钉钉第三方类)之后获取token值的具体接口如下:

public function getToken(Request $request)
{
    $data = DB::table('token')->first();
    if ($data && (time() - $data->addtime) > 7200) {
        $c = new \DingTalkClient(\DingTalkConstant::$CALL_TYPE_OAPI, \DingTalkConstant::$METHOD_GET, \DingTalkConstant::$FORMAT_JSON);
        $req = new \OapiGettokenRequest();
        $corpid =  $this->corpid;
        $corpSecret = $this->corpSecret;
        $req->setCorpid($corpid);
        $req->setCorpsecret($corpSecret);
        $resp = $c->execute($req, '', "https://oapi.dingtalk.com/gettoken");
        $token = $resp->access_token;
        $res = DB::table('token')->where('id',$data->id)->update(['token' => $token, 'addtime' => time()]);
    }elseif(!$data){
        $c = new \DingTalkClient(\DingTalkConstant::$CALL_TYPE_OAPI, \DingTalkConstant::$METHOD_GET, \DingTalkConstant::$FORMAT_JSON);
        $req = new \OapiGettokenRequest();
        $corpid =  $this->corpid;
        $corpSecret = $this->corpSecret;
        $req->setCorpid($corpid);
        $req->setCorpsecret($corpSecret);
        $resp = $c->execute($req, '', "https://oapi.dingtalk.com/gettoken");
        $token = $resp->access_token;
        $res = DB::table('token')->insert(['token' => $token, 'addtime' => time()]);
    }else{
        $token = $data->token;
    }
    return $token;
}
<think>我们使用钉钉开放平台的接口来获取企业内部所有用户信息。主要步骤如下: 1. 获取access_token 2. 获取所有部门列表(因为用户是按部门组织的) 3. 遍历每个部门,获取部门下的用户详情(注意:钉钉API中获取部门用户列表接口可以获取到部门下的用户userid列表,但是要获取详细信息需要再调用用户详情接口) 4. 将每个部门的用户信息合并 但是要注意:钉钉API有两个版本(旧版和新版),这里我们使用新版的V2接口。 参考引用[2]中提到,获取用户信息需要先获取部门列表,然后获取每个部门的用户userid列表,再根据userid获取用户详情。 具体步骤: 步骤1:获取access_token(与之前获取部门信息相同) 步骤2:获取所有部门ID(可以使用之前的方法获取所有部门) 步骤3:遍历每个部门ID,调用“获取部门用户userid列表”接口(/topapi/v2/user/listid)得到userid列表 步骤4:根据userid列表,调用“获取用户详情”接口(/topapi/v2/user/get)获取每个用户的详细信息 但是,钉钉也提供了直接获取部门用户详情列表的接口(/topapi/v2/user/list),该接口可以一次性获取部门下用户的详细信息(需要指定部门id)。因此,我们可以简化步骤3和4,直接使用这个接口。 然而,这个接口有分页,需要注意处理分页。 另外,还要注意:获取所有部门后,需要递归获取所有子部门下的用户。 因此,计划: 1. 获取所有部门(包含子部门)的部门ID列表。 2. 对于每个部门ID,使用分页获取该部门下的所有用户详情。 注意:钉钉API调用频率限制,每个应用调用频率限制为20次/秒。 代码实现: 步骤1:获取access_token(复用之前的代码) 步骤2:获取所有部门ID(包括根部门和所有子部门) 我们可以使用之前获取所有部门信息的方法,然后提取部门ID列表。 步骤3:遍历每个部门ID,调用获取部门用户详情列表接口(分页处理)。 接口文档:https://open.dingtalk.com/document/orgapp-server/queries-the-complete-information-of-a-department-user 步骤4:合并所有用户(注意去重,因为一个用户可能属于多个部门,但同一个用户只需要收集一次) 但是,根据钉钉文档,一个用户只能属于一个部门吗?不是,钉钉中一个用户可以在多个部门。因此,我们可能会获取到重复用户(同一个userid)。所以我们在合并时需要根据userid去重。 另外,也可以考虑先获取所有用户的userid(去重),再批量获取用户详情。但是钉钉没有提供批量获取用户详情的接口,所以只能一个一个获取。这样效率较低。 因此,我们选择先按部门获取用户详情列表(该接口返回的是用户的基本信息,已经包含我们需要的详情),然后根据userid去重。 接口:/topapi/v2/user/list 请求方法:POST 请求参数: dept_id: 部门id cursor: 分页游标,第一次传0 size: 分页大小,最大100 返回结果: has_more: 是否还有更多数据 next_cursor: 下一个游标 list: 用户列表 我们编写一个方法来获取一个部门下的所有用户(分页获取)。 步骤5:将每个部门获取到的用户合并到一个Set中(根据userid去重)。 但是注意:用户可能在不同的部门,但同一个用户userid是唯一的。 实现代码: 1. 定义用户信息的数据结构(UserDetail) 2. 获取所有部门ID(包括根部门) 3. 遍历每个部门ID,分页获取该部门下的所有用户,并添加到Set中(根据userid去重) 注意:如果组织架构很大(部门多、用户多),需要控制调用频率,避免超过频率限制。 代码结构: 首先,创建UserDetail类(包含钉钉用户的所有信息,我们只取部分关键字段,如userid, name, mobile, email, position, department_ids等) 然后,编写方法: public Set<UserDetail> getAllUsers(String accessToken, List<Long> deptIds) { // 遍历deptIds,对每个deptId调用分页获取用户的方法 // 合并用户 } 分页获取一个部门下的所有用户: public List<UserDetail> getUsersByDeptId(String accessToken, Long deptId) { // 分页获取,直到没有下一页 } 最后,主程序调用。 由于钉钉API调用频率限制,我们可以在每次调用后sleep一小段时间(比如50毫秒)来避免超限。 下面是具体代码实现: 注意:需要引用钉钉的SDK(如引用[4]中的依赖) 我们使用DefaultDingTalkClient来发送请求。 由于引用[2]中提到,需要申请权限,所以确保在钉钉开发者后台已经为应用添加了以下权限: - 通讯录只读权限(范围:全部员工) - 成员信息权限 开始写代码: </think># 使用Java获取钉钉企业内部所有用户信息的方法 下面我将详细介绍如何使用Java获取钉钉企业内部所有用户信息,包括用户的姓名、部门、职位等详细信息。 ## 实现步骤 ### 1. 准备工作 - 在钉钉开放平台创建企业内部应用 - 获取AppKey和AppSecret - 申请接口权限:`通讯录只读权限`(范围:全部员工) - 添加Maven依赖(参考引用[4]) ```xml <dependency> <groupId>com.aliyun</groupId> <artifactId>alibaba-dingtalk-service-sdk</artifactId> <version>2.0.0</version> </dependency> ``` ### 2. 获取Access Token(复用之前的代码) ```java import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiGettokenRequest; import com.dingtalk.api.response.OapiGettokenResponse; public class DingTalkAuthService { private static final String ACCESS_TOKEN_URL = "https://oapi.dingtalk.com/gettoken"; public String getAccessToken(String appKey, String appSecret) throws Exception { DingTalkClient client = new DefaultDingTalkClient(ACCESS_TOKEN_URL); OapiGettokenRequest request = new OapiGettokenRequest(); request.setAppkey(appKey); request.setAppsecret(appSecret); request.setHttpMethod("GET"); OapiGettokenResponse response = client.execute(request); if (response.isSuccess()) { return response.getAccessToken(); } else { throw new RuntimeException("获取access_token失败: " + response.getErrmsg()); } } } ``` ### 3. 获取所有用户信息 ```java import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiV2UserListRequest; import com.dingtalk.api.response.OapiV2UserListResponse; import com.dingtalk.api.request.OapiV2UserGetRequest; import com.dingtalk.api.response.OapiV2UserGetResponse; import java.util.ArrayList; import java.util.List; public class DingTalkUserService { // 获取所有部门ID列表 public List<Long> getAllDepartmentIds(String accessToken) throws Exception { // 这里复用之前获取所有部门信息的方法 // 实际实现中应调用获取部门列表API // 返回所有部门ID的列表 List<Long> deptIds = new ArrayList<>(); deptIds.add(1L); // 根部门ID // 添加其他部门ID... return deptIds; } // 分页获取部门下的用户userid列表 private List<String> getUserIdsByDept(String accessToken, Long deptId) throws Exception { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/listid"); OapiV2UserListRequest request = new OapiV2UserListRequest(); request.setDeptId(deptId); request.setCursor(0L); // 从0开始分页 request.setSize(100L); // 每页最大100条 List<String> userIds = new ArrayList<>(); long cursor = 0; boolean hasMore = true; while (hasMore) { request.setCursor(cursor); OapiV2UserListResponse response = client.execute(request, accessToken); if (response.isSuccess()) { OapiV2UserListResponse.PageResult result = response.getResult(); userIds.addAll(result.getList()); hasMore = result.getHasMore(); cursor = result.getNextCursor(); } else { throw new RuntimeException("获取部门用户ID列表失败: " + response.getErrmsg()); } // 避免频繁调用触发限流 Thread.sleep(200); } return userIds; } // 获取单个用户详细信息 private UserDetail getUserDetail(String accessToken, String userId) throws Exception { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); OapiV2UserGetRequest request = new OapiV2UserGetRequest(); request.setUserid(userId); request.setLanguage("zh_CN"); OapiV2UserGetResponse response = client.execute(request, accessToken); if (response.isSuccess()) { OapiV2UserGetResponse.UserGetResponse user = response.getResult(); return new UserDetail( user.getUserid(), user.getName(), user.getMobile(), user.getEmail(), user.getTitle(), // 职位 user.getDeptIdList(), // 所属部门ID列表 user.getAvatar() // 头像URL ); } else { throw new RuntimeException("获取用户详情失败: " + response.getErrmsg()); } } // 获取所有用户详细信息 public List<UserDetail> getAllUsers(String accessToken) throws Exception { List<UserDetail> allUsers = new ArrayList<>(); // 获取所有部门ID List<Long> deptIds = getAllDepartmentIds(accessToken); for (Long deptId : deptIds) { // 获取该部门下的所有用户ID List<String> userIds = getUserIdsByDept(accessToken, deptId); for (String userId : userIds) { // 获取用户详细信息 UserDetail user = getUserDetail(accessToken, userId); allUsers.add(user); // 避免频繁调用触发限流 Thread.sleep(200); } } // 去重(用户可能属于多个部门) return allUsers.stream().distinct().toList(); } // 用户详情类 public static class UserDetail { private String userId; private String name; private String mobile; private String email; private String position; private List<Long> deptIds; private String avatarUrl; public UserDetail(String userId, String name, String mobile, String email, String position, List<Long> deptIds, String avatarUrl) { this.userId = userId; this.name = name; this.mobile = mobile; this.email = email; this.position = position; this.deptIds = deptIds; this.avatarUrl = avatarUrl; } // Getter方法 public String getUserId() { return userId; } public String getName() { return name; } public String getMobile() { return mobile; } public String getEmail() { return email; } public String getPosition() { return position; } public List<Long> getDeptIds() { return deptIds; } public String getAvatarUrl() { return avatarUrl; } @Override public String toString() { return "UserDetail{" + "userId='" + userId + '\'' + ", name='" + name + '\'' + ", mobile='" + mobile + '\'' + ", position='" + position + '\'' + ", deptIds=" + deptIds + '}'; } } } ``` ### 4. 主程序调用 ```java public class MainApplication { public static void main(String[] args) { try { // 1. 获取Access Token DingTalkAuthService authService = new DingTalkAuthService(); String accessToken = authService.getAccessToken("your_app_key", "your_app_secret"); // 2. 获取所有用户信息 DingTalkUserService userService = new DingTalkUserService(); List<DingTalkUserService.UserDetail> users = userService.getAllUsers(accessToken); // 3. 输出结果 System.out.println("====== 钉钉用户列表 ======"); System.out.printf("%-15s %-10s %-15s %-20s %-15s%n", "用户ID", "姓名", "手机号", "职位", "部门ID"); for (DingTalkUserService.UserDetail user : users) { System.out.printf("%-15s %-10s %-15s %-20s %-15s%n", user.getUserId(), user.getName(), user.getMobile(), user.getPosition(), user.getDeptIds()); } System.out.println("====== 共获取 " + users.size() + " 个用户 ======"); } catch (Exception e) { e.printStackTrace(); } } } ``` ## 性能优化建议 1. **批量处理用户详情**: ```java // 批量获取用户详情(每次最多100个用户) private List<UserDetail> getBatchUserDetails(String accessToken, List<String> userIds) throws Exception { // 使用批量获取用户接口(如果可用) // 否则使用多线程并行处理 } ``` 2. **缓存机制**: - 缓存部门信息避免重复查询 - 缓存用户基本信息减少API调用 3. **多线程处理**: ```java ExecutorService executor = Executors.newFixedThreadPool(5); List<Future<UserDetail>> futures = new ArrayList<>(); for (String userId : userIds) { futures.add(executor.submit(() -> getUserDetail(accessToken, userId))); } for (Future<UserDetail> future : futures) { allUsers.add(future.get()); } ``` ## 注意事项 1. **权限申请**: - 确保应用已申请`通讯录只读权限`(全部员工范围) - 权限申请路径:开发者后台 > 应用开发 > 权限管理[^2] 2. **API频率限制**: - 单个企业调用频率:普通权限20次/秒,高级权限40次/秒 - 单个应用调用频率:300次/分钟 - 建议添加限流控制避免触发限制 3. **数据去重**: - 同一个用户可能属于多个部门,需要根据userid去重 - 使用Set集合自动去重或使用Stream distinct() 4. **字段说明**: - 手机号字段可能为空(需员工在钉钉设置可见性) - 头像URL有效期2小时,建议下载保存或使用时实时获取[^3] 5. **错误处理**: - 捕获并处理可能的API异常(权限不足、参数错误等) - 添加重试机制应对临时性网络问题 通过以上方法,您可以高效获取钉钉企业内部所有用户信息,为人员管理、权限分配等场景提供数据支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值