第三方网站实现钉钉(DingTalk)扫码登陆(Vue+SpringBoot)
Posted 曹寰&
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三方网站实现钉钉(DingTalk)扫码登陆(Vue+SpringBoot)相关的知识,希望对你有一定的参考价值。
第三方网站实现钉钉(DingTalk)扫码登陆(Vue+SpringBoot)
一,本地库添加钉钉UserId字段
字段类型VarChar,管理者的userid为String,其余为Long
二,钉钉开放平台配置回调域名。
三,前端构造扫码登录页面。
(1)配置需要参数
appid: '钉钉APiID',
redirectUrl: '回调地址,当前登陆页面地址',
apiUrl: '请求后端地址',
//二维码设置参数
dingCodeConfig:
id: 'login_container',
style: 'border:none;background-color:#FFFFFF;',
width: '365',
height: '400'
(3)构建请求钉钉服务器URL
getRedirectUrl()
return encodeURIComponent(this.redirectUrl)
,
getAuthUrl()
return `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=$this.appid&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=$this.getRedirectUrl`
,
getGoto()
return encodeURIComponent(this.getAuthUrl)
,
getDingCodeConfig()
return ...this.dingCodeConfig, goto: this.getGoto
(4)初始化函数,请求函数
initDingJs()
!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)
,
addDingListener()
let self = this
let handleLoginTmpCode = function(loginTmpCode)
window.location.href = self.getAuthUrl + `&loginTmpCode=$loginTmpCode`
let handleMessage = function(event)
if (event.origin == 'https://login.dingtalk.com')
handleLoginTmpCode(event.data)
if (typeof window.addEventListener != 'undefined')
window.addEventListener('message', handleMessage, false)
else if (typeof window.attachEvent != 'undefined')
window.attachEvent('onmessage', handleMessage)
,
initDingLogin()
window.DDLogin(this.getDingCodeConfig)
四,钉钉回调至登陆页面,前端获取临时授权码。
let getQueryString = function(name)
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
var r = window.location.search.substr(1).match(reg)
if (r != null)
return unescape(r[2])
return null
五,前端携带临时授权码向后端请求。
let code = getQueryString('code')
if (code !== null)
axios
.get(`$this.apiUrl?code=$code`).then(response =>
setToken(response.data.token)
this.$router.push( path: this.redirect || '/' ).catch(() =>
)
commit('SET_TOKEN', response.data.token)
)
.catch(error =>
console.log(error)
)
六, 后端接受请求
@GetMapping("/dingTalkLogin")
public AjaxResult dingTalkLogin(@RequestParam("code") String code)
AjaxResult ajax=null;
// 生成令牌
String token = loginService.dingTalkLogin(code);
if (token != null)
ajax = AjaxResult.success();
ajax.put(Constants.TOKEN, token);
else
ajax = AjaxResult.error("登陆失败,请联系管理员或账号登陆");
return ajax;
七,后端使用临时授权码请求钉钉服务器,获取钉钉UserId
/**
* 钉钉登录
* @return 结果
*/
public String dingTalkLogin(String code)
OapiSnsGetuserinfoBycodeResponse bycodeResponse = null;
// 获取access_token,注意正式代码要有异常流处理
String access_token = Access_tokenUtil.getDingTalkAccess_token();
try
// 通过临时授权码获取授权用户的个人信息
DefaultDingTalkClient client2 = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
OapiSnsGetuserinfoBycodeRequest reqBycodeRequest = new OapiSnsGetuserinfoBycodeRequest();
// 通过扫描二维码,跳转指定的redirect_uri后,向url中追加的code临时授权码
reqBycodeRequest.setTmpAuthCode(code);
bycodeResponse = client2.execute(reqBycodeRequest, DingTalkConstant.DINGTALK_APPKEY, DingTalkConstant.DINGTALK_APPSECRST);
// 根据unionid获取userid
String unionid = bycodeResponse.getUserInfo().getUnionid();
DingTalkClient clientDingTalkClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid");
OapiUserGetbyunionidRequest reqGetbyunionidRequest = new OapiUserGetbyunionidRequest();
reqGetbyunionidRequest.setUnionid(unionid);
OapiUserGetbyunionidResponse oapiUserGetbyunionidResponse = clientDingTalkClient.execute(reqGetbyunionidRequest, access_token);
String userid = oapiUserGetbyunionidResponse.getResult().getUserid();
catch (ApiException e)
e.printStackTrace();
return null;
八,后端根据钉钉UserId获取库中用户信息
/**
* 钉钉登录
* @return 结果
*/
public String dingTalkLogin(String code)
// 根据userId获取用户信息
String userid = oapiUserGetbyunionidResponse.getResult().getUserid();
//更加userID查询用户
SysUser user=sysUserMapper.selectUserByDingTalkUserId(userid);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
//生成loginUser
LoginUser loginUser =(LoginUser) userDetailsService.createLoginUser(user);
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
catch (ApiException e)
e.printStackTrace();
return null;
九,后端跳过Spring Security验证,直接构建LoginUser
跳过UsernamePasswordAuthenticationToken,用户名密码验证
/**
* 钉钉登录
* @return 结果
*/
public String dingTalkLogin(String code)
// 根据userId获取用户信息
String userid = oapiUserGetbyunionidResponse.getResult().getUserid();
//生成loginUser
LoginUser loginUser =(LoginUser) userDetailsService.createLoginUser(user);
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
catch (ApiException e)
e.printStackTrace();
return null;
附1,前端完整源码
<template>
<div id="app">
<div id="login_container"></div>
</div>
</template>
<script>
import axios from 'axios'
import setToken from '@/utils/auth'
export default
components: ,
data()
return
redirect: undefined,
appid: 'ding8lrom1le5zopavwt',
redirectUrl: 'http://localhost:9527/login?redirect=%2Findex',
apiUrl: 'http://localhost:8080/dingTalk/user/dingTalkLogin',
dingCodeConfig:
id: 'login_container',
style: 'border:none;background-color:#FFFFFF;',
width: '365',
height: '400'
,
watch:
$route:
handler: function(route)
this.redirect = route.query && route.query.redirect
,
immediate: true
,
computed:
getRedirectUrl()
return encodeURIComponent(this.redirectUrl)
,
getAuthUrl()
return `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=$this.appid&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=$this.getRedirectUrl`
,
getGoto()
return encodeURIComponent(this.getAuthUrl)
,
getDingCodeConfig()
return ...this.dingCodeConfig, goto: this.getGoto
,
created()
this.initDingJs()
,
mounted()
this.addDingListener()
this.initDingLogin()
this.getUser()
,
methods:
initDingJs()
!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)
,
addDingListener()
let self = this
let handleLoginTmpCode = function(loginTmpCode)
window.location.href = self.getAuthUrl + `&loginTmpCode=$loginTmpCode`
let handleMessage = function(event)
if (event.origin == 'https://login.dingtalk.com')
handleLoginTmpCode(event.data)
if (typeof window.addEventListener != 'undefined')
window.addEventListener('message', handleMessage, false)
else if (typeof window.attachEvent != 'undefined')
window.attachEvent('onmessage', handleMessage)
,
initDingLogin()
window.DDLogin(this.getDingCodeConfig)
,
getUser()
let getQueryString = function(name)
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
var r = window.location.search.substr(1).match(reg)
if (r != null)
return unescape(r[2])
return null
let code = getQueryString('code')
if (code !== null)
axios
.get(`$this.apiUrl?code=$code`).then(response =>
setToken(response.data.token)
this.$router.push( path: this.redirect || '/' ).catch(() =>
)
commit('SET_TOKEN', response.data.token)
)
.catch(error =>
console.log(error)
)
</script>
附2,后端完整源码s
(1)Controller
/**
* 钉钉扫码登录方法
*
* @param code 扫码返回code
* @return 结果
*/
@GetMapping("/dingTalkLogin")
public AjaxResult dingTalkLogin(@RequestParam("code") String code第三方网站实现钉钉(DingTalk)扫码登陆(Vue+SpringBoot)