你需要一个自己的团队,或则某个团队你有管理权限,否则注册个吧,注册钉钉的账号,以获取APPID;https://oa.dingtalk.com/register.html),
获取AAPID
官方文档地址:https://developers.dingtalk.com/document/app/scan-qr-code-to-log-on-to-third-party-websites?spm=a2q3p.21071111.0.0.18711cfa4kzCXi
APPID:为上图创建的appld
REDIRECT_URI:为回调域名
随便建一个index.htm文件(下面有vue工程实践完整代码,以及nodeJs接口的实现)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="http://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js">script>
head>
<body>
<div id="login_container">div>
<script>
let APPID = "dingoarrgitdv8zv6z9l4r"
// let REDIRECT_URI = encodeURIComponent("http://127.0.0.1:8080/")
let REDIRECT_URI = "http://127.0.0.1:8080/"
let goto = `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=${APPID}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=${REDIRECT_URI}`
console.log('goto',goto)
var obj = DDLogin({
id: "login_container",
goto: encodeURIComponent(goto),
style: "border:none;background-color:#FFFFFF;",
width: "365",
height: "400"
});
var hanndleMessage = function (event) {
var origin = event.origin;
console.log("origin", event.origin);
if (origin == "https://login.dingtalk.com") { //判断是否来自ddLogin扫码事件。
var loginTmpCode = event.data; //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了
console.log("loginTmpCode", loginTmpCode);
window.location.href = goto + '&loginTmpCode='+loginTmpCode
}
};
if (typeof window.addEventListener != 'undefined') {
window.addEventListener('message', hanndleMessage, false);
} else if (typeof window.attachEvent != 'undefined') {
window.attachEvent('onmessage', hanndleMessage);
}
script>
body>
html>
https://oapi.dingtalk.com/sns/gettoken?appid=APPID&appsecret=APPSECRET
{
"errcode": 0,
"access_token": "9c971e5a98839cda1fb33359bda8ade7",
"errmsg": "ok"
}
https://oapi.dingtalk.com/sns/get_persistent_code?access_token=ACCESS_TOKEN
ACCESS_TOKEN ==> 9c971e5a98839cda1fb33359bda8ade7
↓
https://oapi.dingtalk.com/sns/get_persistent_code?access_token=9c971e5a98839cda1fb33359bda8ade7
post参数:
{
"tmp_auth_code": "2d53880fa733d1218ca43301af99df60"
}
//2d53880fa733d1218ca43301af99df60为跳转后url中的code值
{
"errcode": 0,
"errmsg": "ok",
"unionid": "Wplnhq6S5AiEiEl109aXgNmiPF9",
"openid": "dHUTIdKEiEiu0s4nD1yWMz9iJQi",
"persistent_code": "lABB9Jqul44p3rYf8fck2vWAmunia0ptigj8XEV82c2oYYCPxUNYD17CHR_UBkRv"
}
https://oapi.dingtalk.com/sns/get_sns_token?access_token=ACCESS_TOKEN
#ACCESS_TOKEN跟上面一样
post参数:
{
"openid": "dHUTIdKEiEiu0s4nD1yWMz9iJQi",
"persistent_code": "lABB9Jqul44p3rYf8fck2vWAmunia0ptigj8XEV82c2oYYCPxUNYD17CHR_UBkRv
}
反馈结果
{
"errcode": 0,
"errmsg": "ok",
"sns_token": "258a8bbe0c3f8e998e4771903b4d3bdf",
"expires_in": 7200
}
https://oapi.dingtalk.com/sns/getuserinfo?sns_token=SNS_TOKEN
#SNS_TOKEN 258a8bbe0c3f8e998e4771903b4d3bdf
反馈结果
{
"errcode": 0,
"errmsg": "ok",
"user_info": {
"nick": "李三",
"unionid": "F9hgNplni6S5Al10miP9aXqEiEW",
"dingId": "$:LWCP_v1:$XhiZhvS6S1Bl/J9A7JrVZuP8usS0/3pi",
"openid": "dHUEiyWMz9TIdKEiiu0s4nD1JQi"
}
}
简单搭建一个node服务器,调用钉钉接口返回信息
需要安装:
npm i express #node框架
npm i axios #xhr
npm i cors #跨域
const express = require('express')
const axios = require('axios');
const app = express()
//解决跨域
const cors = require('cors');
app.use(cors())
const api = axios.create({
baseURL: 'https://oapi.dingtalk.com/sns'
})
//钉钉接口
//获取access_token
const gettoken = params => {
return api({
url: '/gettoken',
method: 'get',
params
});
};
//获取授权码
const get_persistent_code = ({ access_token, tmp_auth_code }) => {
return api({
url: '/get_persistent_code?access_token=' + access_token,
method: 'post',
data: {
tmp_auth_code
}
});
};
//获取用户授权的SNS_TOKEN
const get_sns_token = ({ access_token, openid, persistent_code }) => {
return api({
url: '/get_sns_token?access_token=' + access_token,
method: 'post',
data: {
openid,
persistent_code
}
});
};
//用户信息
const getuserinfo = params => {
return api({
url: '/getuserinfo',
method: 'get',
params
});
};
//变量声明
const appid = "dingoarrgitdv8zv6z9l4r"
const appsecret = "_7ru7LMqtWNvvAsXxKzGhQkvwqYB24PecCnjB0vZ_GY5Pt9YXtKpkDeVFZSC-eu0"
app.get('/', (req, res, next) => {
const { tmp_auth_code } = req.query
gettoken({ appid, appsecret })
.then(response => {
const { access_token } = response.data
console.log('access_token:', access_token)
return get_persistent_code({
access_token,
tmp_auth_code
})
})
.then(response => {
// console.log(response)
const access_token = response.config.url.split('=')[1]
const { openid, persistent_code } = response.data
console.log('access_token:', access_token)
console.log('openid:', openid)
console.log('persistent_code:', persistent_code)
return get_sns_token({ openid, persistent_code, access_token })
})
.then(response => {
const { sns_token } = response.data
console.log('sns_token:', sns_token)
return getuserinfo({ sns_token })
})
.then(response => {
console.log(response.data)
// const { nick, unionid, dingId, openid } = response.data
res.send(response.data.user_info)
})
.catch(error => {
console.log(error)
})
})
app.listen(3000, () => {
console.log('3000端口服务器启动成功')
})
#启动服务器
node app.js
vue-cli简单搭建一个vue工程,vue-cli自己看下文档创建
将上面的index.html整合到工程里
安装:
npm i axios
vuecli2直接在vue.config.js添加如下内容即可,vueCli3 webpack配置信息都被隐藏了,所以在src同级目录下创建vue.config.js内容如下:
配置cdn引入
module.exports = {
configureWebpack: {
externals: {
'DDLogin': 'DDLogin',
}
},
};
public文件下的index.html需要引入钉钉的DDLogin方法
DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %>title>
head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
noscript>
<div id="app">div>
<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js">script>
body>
html>
在vue工程中的app.vue文件内容如下
<template>
<div id="app">
<div id="login_container">div>
<div v-if="JSON.stringify(res) != '{}'">
<div v-if ="res.errcode == undefined">
dingId:{{ res.nick }}
<hr />
nick:{{ res.dingId }}
<hr />
openid:{{ res.openid }}
<hr />
unionid:{{ res.unionid }}
<hr />
div>
<div v-else>
errcode:{{ res.errcode }}
<hr />
error:{{ res.errmsg }}
<hr />
div>
div>
div>
template>
<script>
import axios from "axios";
// import HelloWorld from './components/HelloWorld.vue'
const api = axios.create({
baseURL: "http://127.0.0.1:3000/",
});
const getUserInfo = (params) => {
return api({
url: "/",
method: "get",
params,
});
};
export default {
name: "App",
data() {
return {
res: {},
};
},
mounted() {
this.loginInto();
},
methods: {
loginInto() {
/**
* 如果初次开启该页面的话,url参数没有code的值,因此此次进入页面为扫码
* 当扫码成功,再次登陆该页面的时候,url会携带code参数,此次为扫码登陆后,则展示个人信息
*/
//判断路径中是否含有code
const hrefIndex = window.location.href.indexOf("code=");
if (hrefIndex === -1) {
//首次进入页面,扫码
//扫码相关
let APPID = "dingoarrgitdv8zv6z9l4r";
// let REDIRECT_URI = encodeURIComponent("http://127.0.0.1:8080/")
let REDIRECT_URI = "http://127.0.0.1:8080/";
// REDIRECT_URI = window.location.href
let goto = `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=${APPID}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=${REDIRECT_URI}`;
console.log("goto", goto);
window.DDLogin({
id: "login_container",
goto: encodeURIComponent(goto),
style: "border:none;background-color:#FFFFFF;",
width: "365",
height: "400",
});
var hanndleMessage = function (event) {
var origin = event.origin;
console.log("origin", event.origin);
if (origin == "https://login.dingtalk.com") {
//判断是否来自ddLogin扫码事件。
var loginTmpCode = event.data; //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了
// console.log("loginTmpCode", loginTmpCode);
window.location.href = goto + "&loginTmpCode=" + loginTmpCode;
}
};
if (typeof window.addEventListener != "undefined") {
window.addEventListener("message", hanndleMessage, false);
} else if (typeof window.attachEvent != "undefined") {
window.attachEvent("onmessage", hanndleMessage);
}
} else {
//再次进入该页面,调用钉钉接口展示个人信息
//获取路径中code参数
// console.log('window.location.search',window.location.search)
const tmp_auth_code = window.location.search
.split("&")[0]
.split("=")[1];
// console.log('tmp_auth_code',tmp_auth_code)
//调用接口
getUserInfo({ tmp_auth_code })
.then((response) => {
console.log("response", response);
// this.res = response.data;
const { errcode, user_info } = response.data;
if (errcode == 0) {
this.res = user_info;
} else {
this.res = response.data;
}
})
.catch((error) => {
this.res = error;
});
}
},
},
};
script>
<style scoped>
.heng {
color: red;
}
style>
关于官方文档直接使用DDLogin({}),而我的使用window.DDLogin({}),是因为汇报这个错误:
解决思路是:我浏览器看了https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js下的代码:
!function (window, document) {
function d(a) {
var e, c = document.createElement("iframe"),
d = "https://login.dingtalk.com/login/qrcode.htm?goto=" + a.goto ;
d += a.style ? "&style=" + encodeURIComponent(a.style) : "",
d += a.href ? "&href=" + a.href : "",
c.src = d,
c.frameBorder = "0",
c.allowTransparency = "true",
c.scrolling = "no",
c.width = a.width ? a.width + 'px' : "365px",
c.height = a.height ? a.height + 'px' : "400px",
e = document.getElementById(a.id),
e.innerHTML = "",
e.appendChild(c)
}
window.DDLogin = d
}(window, document);
window.DDLogin = dDDLogin被挂到了window上面了,所以。。。。。具体情况看你们自己了
"对不起 你无权限查看该页面 redirect_url不能为空"
原因:
1. 只对redirect_url编码,而生成二维码时需要对整个gotoUrl进行编码
2. appid参数值后有空格,编码后空格编码成"+"号
"对不起,你无权限查看该页面,redirect_url的域名不在appid安全域名内"
原因:
1. 应用配置域名和二维码绘制时使用的redirect_url不是同一个域名
如
应用域名: http://ji.wicp.vip/jsoa/dingdingScanLoginAction.do
二维码域名:http://ji.wicp1.vip/jsoa/dingdingScanLoginAction.do
2. 相同域名,但是应用回调域名中的path和后台配置的path不一致时,不影响用户扫码登录
如
应用域名: http://ji.wicp.vip/XXXX
二维码域名:http://ji.wicp.vip/js/dingdingScanLoginAction.do
用户登录扫码后,什么反应也没有,事件监听函数var hanndleMessage = function (event) {}没有捕获到事件
原因:
1. state后面有空格或者redirect_url中有空格,此时IOS和安卓用户扫码后,可以点击登陆但是点击登录后无响应,页面接收不到回调