{"id":24879851,"url":"https://github.com/klren0312/dingdingqrcodelogindemo","last_synced_at":"2025-04-13T14:12:56.833Z","repository":{"id":223979467,"uuid":"761686197","full_name":"klren0312/dingdingQrcodeLoginDemo","owner":"klren0312","description":"钉钉扫码登录demo 使用NodeJS","archived":false,"fork":false,"pushed_at":"2024-02-23T03:02:02.000Z","size":510,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-13T14:12:52.694Z","etag":null,"topics":["dingding","express"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klren0312.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-02-22T09:49:20.000Z","updated_at":"2025-04-02T02:53:21.000Z","dependencies_parsed_at":"2024-02-23T04:52:04.508Z","dependency_job_id":"3021288a-0451-493b-abd1-2eb07298c9ca","html_url":"https://github.com/klren0312/dingdingQrcodeLoginDemo","commit_stats":null,"previous_names":["klren0312/dingdingqrcodelogindemo"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klren0312%2FdingdingQrcodeLoginDemo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klren0312%2FdingdingQrcodeLoginDemo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klren0312%2FdingdingQrcodeLoginDemo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klren0312%2FdingdingQrcodeLoginDemo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klren0312","download_url":"https://codeload.github.com/klren0312/dingdingQrcodeLoginDemo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248724629,"owners_count":21151561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dingding","express"],"created_at":"2025-02-01T10:17:55.312Z","updated_at":"2025-04-13T14:12:56.810Z","avatar_url":"https://github.com/klren0312.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 钉钉扫码登录demo\n\u003e 基于Nodejs\n\n## 安装依赖\n```shell\npnpm install\n```\n## 运行\n```shell\npnpm start\n# 访问 http://localhost:3000\n```\n\n## 参考资料\n\n - [实现登录第三方网站](https://open.dingtalk.com/document/isvapp/tutorial-enabling-login-to-third-party-websites)\n - [获取用户token api文档](https://open.dingtalk.com/document/orgapp/obtain-user-token#)\n\n\n## 1. 查看文档\n\u003e [实现登录第三方网站](https://open.dingtalk.com/document/isvapp/tutorial-enabling-login-to-third-party-websites)\n\n官方文档中开放平台截图和真实环境不一致，所以记录下\n\n## 2. 创建应用\n\u003e [钉钉开放平台](https://open.dingtalk.com/)\n\n1.登录后, 选择顶部导航栏`应用开发`, 再选择侧边栏`钉钉应用`, 点击右侧`创建应用`\n![](./docImages/1.png)\n\n2.输入信息后点击保存\n![](./docImages/2.png)\n\n3.进入应用, 点击侧边栏`凭证与基础信息`, 先记录`client_id`和`client_secret`, 这个前后端都需要用到\n![](./docImages/3.png)\n\n4.点击`权限管理`, 选中`个人手机号信息`和`通讯录个人信息读权限`, 方便登录后获取登录人的信息(仅demo演示)\n\u003e [权限文档](https://open.dingtalk.com/document/isvapp/dingtalk-retrieve-user-information)\n\n![](./docImages/4.png)\n\n开通`通讯录个人信息读权限`需要`个人手机号信息`的辅助\n![](./docImages/5.png)\n\n5.点击`分享设置`, 接入登录的回调域名后面配置成后端接口地址\n![](./docImages/6.png)\n\n## 3. 后端开发\n### 1) 安装依赖\n```bash\npnpm init\npnpm add @alicloud/dingtalk @alicloud/openapi-client @alicloud/tea-util\n```\n\n**注意:** 使用SDK开发时, 可以进入到node_modules中查看sdk源码, 了解代码结构, 方便引入代码和调用方法, 感觉挺乱的\n\n### 2) 获取用户授权方法\n```js\nconst config = new $OpenApi.Config({ })\nconfig.protocol = 'https'\nconfig.regionId = 'central'\nconst client = new oauth2_1_0.default(config)\nconst getUserTokenRequest = new oauth2_1_0.GetUserTokenRequest({\n  clientId: CLIENTID,\n  clientSecret: CLIENTSECRET,\n  code: req.query.authCode,\n  refreshToken: '',\n  grantType: 'authorization_code',\n})\n```\n\n### 3) 根据授权的token查询用户信息\n```js\nasync function getUserInfo (accessToken) {\n  const config = new $OpenApi.Config({ })\n  config.protocol = 'https'\n  config.regionId = 'central'\n  const client = new contact_1_0.default(config)\n  const getUserHeader = new contact_1_0.GetUserHeaders()\n  getUserHeader.xAcsDingtalkAccessToken = accessToken\n  const infoRes = await client.getUserWithOptions('me', getUserHeader, new $Util.RuntimeOptions())\n  return infoRes\n}\n```\n\n### 4) 完整代码\n```js\nimport express from 'express'\nimport { contact_1_0, oauth2_1_0 } from '@alicloud/dingtalk'\nimport * as $OpenApi from '@alicloud/openapi-client'\nimport * as $Util from '@alicloud/tea-util'\n\nconst CLIENTID = '' // 应用 client_id\nconst CLIENTSECRET = '' // 应用 client_secret\n\nconst app = express()\napp.use(express.static('public'))\n\n/**\n * 获取用户授权\n */\napp.get('/auth', async (req, res) =\u003e {\n  const config = new $OpenApi.Config({ })\n  config.protocol = 'https'\n  config.regionId = 'central'\n  const client = new oauth2_1_0.default(config)\n  const getUserTokenRequest = new oauth2_1_0.GetUserTokenRequest({\n    clientId: CLIENTID,\n    clientSecret: CLIENTSECRET,\n    code: req.query.authCode,\n    refreshToken: '',\n    grantType: 'authorization_code',\n  })\n  try {\n    const result = await client.getUserToken(getUserTokenRequest)\n    const info = await getUserInfo(result.body.accessToken)\n    res.json({\n      data: {\n        ackey: result.body,\n        info: info.body\n      }\n    })\n  } catch (err) {\n    console.log(err)\n  }\n})\n\napp.listen(3000, () =\u003e {\n  console.log(`Example app listening on port 3000`)\n})\n\n/**\n * 获取用户信息\n * @param {string} accessToken\n * @returns 用户信息返回体\n */\nasync function getUserInfo (accessToken) {\n  const config = new $OpenApi.Config({ })\n  config.protocol = 'https'\n  config.regionId = 'central'\n  const client = new contact_1_0.default(config)\n  const getUserHeader = new contact_1_0.GetUserHeaders()\n  getUserHeader.xAcsDingtalkAccessToken = accessToken\n  const infoRes = await client.getUserWithOptions('me', getUserHeader, new $Util.RuntimeOptions())\n  return infoRes\n}\n\n\n```\n\n## 4. 前端开发\n\u003e 内嵌二维码方式登录授权\n\n### 1) 前端页面位置\n\n需要注意, 要把前端页面和后端服务地址配在同域名端口协议下.(嵌入二维码的页面必须和redirect_uri参数所指定的页面“同源”，否则扫码后会没有反应，“同源”指：协议相同、二级或三级域名相同、端口号相同等。)\n\n由于是demo, 所以直接用express提供静态服务(`app.use(express.static('public'))`), 把index.html放在public目录, 来进行前端访问, 也可以使用nginx\n\n### 2) 引入钉钉登录的包\n```html\n\u003cscript src=\"https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js\"\u003e\u003c/script\u003e\n```\n\n### 3) 编写逻辑\n需要创建一个div, 用于钉钉在其中创建二维码, 二维码是存在于`iframe`中的\n\n`redirect_uri`需要跟开放平台配置的回调地址一样\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"UTF-8\" /\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n    \u003ctitle\u003eDocument\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cdiv id=\"self_defined_element\"\u003e\u003c/div\u003e\n    \u003ctextarea id=\"js-info\" cols=\"30\" rows=\"10\"\u003e\u003c/textarea\u003e\n    \u003cscript src=\"https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n      // STEP3：在需要的时候，调用 window.DTFrameLogin 方法构造登录二维码，并处理登录成功或失败的回调。\n      window.DTFrameLogin(\n        {\n          id: 'self_defined_element',\n          width: 300,\n          height: 300,\n        },\n        {\n          redirect_uri: encodeURIComponent(''), // 应用配的登录回调地址\n          client_id: '', // 应用的client_id\n          scope: 'openid',\n          response_type: 'code',\n          prompt: 'consent',\n        },\n        async (loginResult) =\u003e {\n          document.getElementById('self_defined_element').style.display = 'none'\n          const { redirectUrl } = loginResult\n          // 请求后端接口, 获取用户信息\n          const res = await fetch(redirectUrl).then(res =\u003e res.json())\n          document.getElementById('js-info').value = JSON.stringify(res.data)\n        },\n        (errorMsg) =\u003e {\n          alert(`Login Error: ${errorMsg}`);\n        }\n      );\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## 5. 结果\n由于使用内嵌二维码登录授权的方式, 所以用户跳转需要自己触发\n\n![](./docImages/7.png)\n\n![](./docImages//8.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklren0312%2Fdingdingqrcodelogindemo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklren0312%2Fdingdingqrcodelogindemo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklren0312%2Fdingdingqrcodelogindemo/lists"}