钉钉第三方登录官方地址https://open.dingtalk.com/document/orgapp/tutorial-obtaining-user-personal-information
1.准备好前期工作
2.编写授权地址
https://login.dingtalk.com/oauth2/auth?
redirect_uri=http://127.0.0.1:8000/ding_back/ #重定向的地址
&response_type=code
&client_id=dingxxxxxxx #应用的AppKey
&scope=openid #此处的openId保持不变
&prompt=consent
3.接收前端参数,换取token
POST /v1.0/oauth2/userAccessToken HTTP/1.1
Host:api.dingtalk.com
Content-Type:application/json
{
"clientId" : "String",
"clientSecret" : "String",
"code" : "String",
"refreshToken" : "String",
"grantType" : "String"
}
code = self.get_argument("authCode")
# 根据code换取token
async with httpx.AsyncClient() as client:
ding_info = await client.post(url="https://api.dingtalk.com/v1.0/oauth2/userAccessToken",
json={
"clientId": SITE_TYPE["Dingding"]["client_id"],
"clientSecret": SITE_TYPE["Dingding"]["client_secret"],
"code": code,
"grantType": "authorization_code"
})
ding_info_json = json.loads(ding_info.text)
if "expireIn" not in ding_info_json:
return self.finish({
"code": 400,
"msg": "token获取失败,原因%s" % ding_info.text
})
ding_access_token = ding_info_json["accessToken"]
4.根据token换取用户信息
GET /v1.0/contact/users/{unionId} HTTP/1.1
Host:api.dingtalk.com
x-acs-dingtalk-access-token:String
Content-Type:application/json
async def get_info(self, ding_access_token):
# 根据token换取用户信息
async with httpx.AsyncClient() as client:
ding = await client.get(url="https://api.dingtalk.com/v1.0/contact/users/me",
headers={
"x-acs-dingtalk-access-token": ding_access_token
})
ding_json = json.loads(ding.text)
username = ding_json["nick"]
unionId = ding_json["unionId"]
return unionId, username
async def get(self):
ding_id, ding_name = await self.get_info(ding_access_token)
username = (str(ding_id) + "_" + str(ding_name))
5.查看用户是否第一次登录
try:
# 曾经使用过dingding账号
await db.get(UserModel.select().where((UserModel.username == username)
& (UserModel.site_type == SITE_TYPE["Dingding"]["num"])))
except Exception as e:
print(e.args)
res = await db.create(UserModel, username=username,
site_type=SITE_TYPE["Dingding"]["num"])
6.重新生成有生命周期的token
finally:
mj = MyJwt()
# 生成带有生命周期的token
token = mj.encode_date({
"username": username,
"site_type": SITE_TYPE["Dingding"]["num"]
})
# 生成refresh_token redis里面存
refresh_token = await mj.set_refresh_token(username)
url = "http://127.0.0.1:8080/center" + f"?ding_refresh_token={refresh_token}&ding_token={token}&username={username}"
return self.redirect(url)
完整代码
import httpx
# dingding登录
class Dingding(BaseHandler):
async def get_info(self, ding_access_token):
# 根据token换取用户信息
async with httpx.AsyncClient() as client:
ding = await client.get(url="https://api.dingtalk.com/v1.0/contact/users/me",
headers={
"x-acs-dingtalk-access-token": ding_access_token
})
ding_json = json.loads(ding.text)
username = ding_json["nick"]
unionId = ding_json["unionId"]
return unionId, username
async def get(self):
code = self.get_argument("authCode")
# 根据code换取token
async with httpx.AsyncClient() as client:
ding_info = await client.post(url="https://api.dingtalk.com/v1.0/oauth2/userAccessToken",
json={
"clientId": SITE_TYPE["Dingding"]["client_id"],
"clientSecret": SITE_TYPE["Dingding"]["client_secret"],
"code": code,
"grantType": "authorization_code"
})
ding_info_json = json.loads(ding_info.text)
if "expireIn" not in ding_info_json:
return self.finish({
"code": 400,
"msg": "token获取失败,原因%s" % ding_info.text
})
ding_access_token = ding_info_json["accessToken"]
ding_id, ding_name = await self.get_info(ding_access_token)
username = (str(ding_id) + "_" + str(ding_name))
try:
# 曾经使用过dingding账号
await db.get(UserModel.select().where((UserModel.username == username)
& (UserModel.site_type == SITE_TYPE["Dingding"]["num"])))
except Exception as e:
print(e.args)
res = await db.create(UserModel, username=username,
site_type=SITE_TYPE["Dingding"]["num"])
finally:
mj = MyJwt()
# 生成带有生命周期的token
token = mj.encode_date({
"username": username,
"site_type": SITE_TYPE["Dingding"]["num"]
})
# 生成refresh_token redis里面存
refresh_token = await mj.set_refresh_token(username)
url = "http://127.0.0.1:8080/center" + f"?ding_refresh_token={refresh_token}&ding_token={token}&username={username}"
return self.redirect(url)
# 路由
urlpatterns = [
(r"/ding_back/", Dingding), # dingding
]