2026/2/17 10:39:57
网站建设
项目流程
深圳做网站的公司排名,做信贷抢客户网站,模板建站3000是不是贵了,wordpress4.9教程pdf前置条件#xff0c;准备clientid、clientsecrect密钥、回调地址即可#xff08;本地需要自备公网映射#xff09;。 实战案例#xff1a;Spring Boot 快实现钉钉扫码登录
在企业级 OA 系统或内部工具开发中#xff0c;“钉钉扫码登录”是最高频的需求之一。它能利用钉钉…前置条件准备clientid、clientsecrect密钥、回调地址即可本地需要自备公网映射。实战案例Spring Boot 快实现钉钉扫码登录在企业级 OA 系统或内部工具开发中“钉钉扫码登录”是最高频的需求之一。它能利用钉钉的身份认证体系免去用户记忆账号密码的烦恼同时实现企业架构的安全管控。本文基于Spring Boot 2.x和阿里新版 Tea SDK (2.0)还原从配置到代码落地的完整流程重点解决403权限报错和SDK参数类型不匹配等痛点。一、 核心准备工作 (不做必错)在写代码之前必须先在 钉钉开发者后台 完成以下配置。****1. 权限开通 (关键)痛点代码跑通了但最后一步获取用户信息时报错 403 Forbidden。原因未开通通讯录读取权限。解决进入【应用开发】-【权限管理】搜索并申请以下权限✅通讯录个人信息读权限(核心用于获取UnionId和Nick不申请会报 403)✅成员信息读权限(建议一并申请)2. 配置回调域名规则前端代码里的redirect_uri必须与后台配置字符级完全一致。开发配置-回调域名示例http://domain.com:28088/login/callback# 回调你本地或公网的注意请确保包含http://协议头和端口号。二、 项目依赖配置 (Maven)dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.aliyun/groupId artifactIddingtalk/artifactId version2.2.40/version /dependency dependency groupIdcom.aliyun/groupId artifactIdtea-openapi/artifactId version0.3.1/version /dependency dependency groupIdcom.aliyun/groupId artifactIdtea-util/artifactId version0.2.16/version /dependency /dependencies三、 前端实现 (内嵌二维码)使用钉钉官方提供的ddlogin.js可以在页面内通过div容器直接渲染二维码无需跳转页面体验更佳。文件index.htmlHTML!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleOA系统钉钉扫码登录/title script srchttps://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js/script style body { display: flex; justify-content: center; align-items: center; height: 100vh; background: #f0f2f5; } #login_box { background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } /style /head body div idlogin_box/div script // 必须与钉钉后台配置的一模一样 const REDIRECT_URI http://domain.com:28088/login/callback; const CLIENT_ID dingw6c***sfqjrr; // 您的ClientId window.DTFrameLogin( { id: login_box, width: 300, height: 300, }, { redirect_uri: REDIRECT_URI, client_id: CLIENT_ID, scope: openid, // 固定值 response_type: code, // 固定值 state: my_oa_security_token, // 防止CSRF生产环境建议随机生成 prompt: consent, }, (loginResult) { // 扫码成功后钉钉返回 redirectUrl其中包含了 authCode window.location.href loginResult.redirectUrl; }, (errorMsg) { alert(二维码加载失败: JSON.stringify(errorMsg)); } ); /script /body /html四、 后端实现 (核心逻辑)后端逻辑遵循“Code 换 Token - Token 换 UserInfo”的标准流程。package org.example.dingdingscan; import com.aliyun.teaopenapi.models.Config; import com.aliyun.dingtalkoauth2_1_0.Client; import com.aliyun.dingtalkoauth2_1_0.models.*; import com.aliyun.dingtalkcontact_1_0.models.*; import com.aliyun.teautil.models.RuntimeOptions; // 必须引入 import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/login) public class DingLoginController { // 替换为您的真实配置 private static final String CLIENT_ID dingw6cv1****fqjrr; private static final String CLIENT_SECRET uiGdvr7xztEU****uLgmSv0O1nOiPoe0-vmkfYWHxMDAeiDIv42QEFY; GetMapping(/callback) public String callback(RequestParam(authCode) String authCode) { try { // --- 步骤 1初始化基础配置 --- Config config new Config(); config.protocol https; config.regionId central; // --- 步骤 2使用 OAuth2 Client 获取 AccessToken --- Client oauthClient new Client(config); GetUserTokenRequest tokenRequest new GetUserTokenRequest() .setClientId(CLIENT_ID) .setClientSecret(CLIENT_SECRET) .setCode(authCode) .setGrantType(authorization_code); GetUserTokenResponse tokenResponse oauthClient.getUserToken(tokenRequest); String userAccessToken tokenResponse.getBody().getAccessToken(); // --- 步骤 3使用 Contact Client 获取用户信息 --- com.aliyun.dingtalkcontact_1_0.Client contactClient new com.aliyun.dingtalkcontact_1_0.Client(config); GetUserHeaders headers new GetUserHeaders(); headers.setXAcsDingtalkAccessToken(userAccessToken); // 【核心修正点】使用 WithOptions 避免参数类型报错 GetUserResponseBody userBody contactClient.getUserWithOptions( me, // me 代表查询当前用户 headers, new RuntimeOptions() // 运行时参数不可为 null ).getBody(); // --- 步骤 4提取核心数据 --- String dingUserId userBody.getUnionId(); // 全局唯一ID String nick userBody.getNick(); String avatar userBody.getAvatarUrl(); // 在此处对接您的 OA 数据库 // select * from sys_user where union_id dingUserId return div styletext-align:center; padding:50px; h2 登录成功/h2 img src avatar stylewidth:64px;border-radius:50%;br/ b欢迎回来:/b nick br/ bUnionId:/b dingUserId /div; } catch (Exception e) { e.printStackTrace(); return ❌ 登录失败: e.getMessage(); // 常见错误如 403 会在这里捕获 } } }五、 总结与排查速查表在整个实施过程中请对照以下表格自查错误现象可能原因解决方案二维码加载不出来前端client_id或redirect_uri配置错误检查代码与钉钉后台【回调域名】是否完全一致。Code: 403 Forbidden接口权限未开通钉钉后台 - 权限管理 - 申请“通讯录个人信息读权限”。Maven 找不到包依赖版本过旧或模块拆分错误使用dingtalk聚合包版本推荐2.2.40。Required String…SDK 方法签名不匹配改用getUserWithOptions替代getUser。手机号为空企业未认证未认证企业通常无法通过 API 获取手机号建议使用UnionId做账号绑定。通过以上步骤成功实现从扫码到获取用户身份**的完整闭环。该方案代码结构清晰且规避了常见的版本兼容性问题。