vue中 给企业微信自建应用授权(静默授权,手动授权,扫码授权)
在web开发中,会遇到通过企业微信授权的形式进行免登录或快速登录的需求。
如果该应用是企业微信自建应用,那可以在管理平台获取到相应的appId和agentid等必要参数。
企业微信提供了OAuth的授权登录方式,可以让从企业微信终端打开的网页获取成员的身份信息,从而免去登录的环节。
现在已经搭建好vue的项目并且企业微信应用相关参数也已经获取到,那就开始吧。
一、静默授权与手动授权
- 静默授权:用户点击链接后,页面直接302跳转至 redirect_uri?code=CODE&state=STATE
- 手动授权:用户点击链接后,会弹出一个中间页,让用户选择是否授权,用户确认授权后再302跳转至 redirect_uri?code=CODE&state=STATE
构造网页授权链接
https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE&agentid=AGENTID#wechat_redirect
示例:
const redirectUrl = encodeURIComponent(`${window.location.origin}/callback`);
const state = '123'; // 用于防止CSRF攻击,可以是任意字符串
const appId = 'your_app_id'; // 企业微信应用ID
const scope = 'snsapi_base'; // 授权类型,snsapi_base或snsapi_privateinfo
const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
window.location.href = url;
此时会提示在企业微信环境中打开链接,页面将跳转至 redirect_uri?code=CODE&state=STATE,企业可根据code参数获得员工的userid。code长度最大为512字节。
接下来步入正题:在vue项目中配置。
其实vue项目中我们已经做过登录的路由守卫,那现在免登录其实就是对登录逻辑的调整,那就直接载permission.js中修改就行。
在router.beforeEach中进行判断:
1 router.beforeEach((to, from, next) => { 2 const token = getToken() // token 3 const redirectUrl = encodeURIComponent(`${window.location.origin}`) // 重定向url 4 const appId = 'ww****123' // 企业微信ID 5 const scope = 'snsapi_base' // 授权类型,snsapi_base(静默授权)或snsapi_privateinfo(手动授权) 6 const urlState = '123' // 用于防止CSRF攻击,可以是任意字符串 7 const agentid = '123***123' // 企业内应用id 8 const openUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${urlState}&agentid=${agentid}#wechat_redirect` 9 setTimeout(() => { 10 if (token) { // 已登录,有token 11 if (to.path === '/login') { 12 next({ 13 path: '/' 14 }) 15 } else { 16 next() 17 } 18 } else { // 没有token,去授权 19 window.location.href = openUrl 20 } 21 }, 0) 22 })
在 window.location.href = openUrl 后会重定向返回code和state,根据这两个字段来获取用户信息,所以得先判断我们的路由中是否带有这两个字段,如果有要先去除:
1 function delCodeandstate (to) { 2 let path = '' 3 for (const i in to.query) { 4 if (i != 'code' && i != 'state') { 5 path = path + '&' + i + '=' + to.query[i] 6 } 7 } 8 path = path == '' ? '' : path.substring(1, path.length) 9 path = path == '' ? '' : '/?' + path 10 return path 11 }
注意:因为企业微信返回的code和state是固定的,所以避免判断出现混淆,我们在路由切换中避免使用code和state作为传参关键字,清除链接中的code和state避免页面反复跳转。
如果获取到code和state,还要和token一起作为判断条件,判断token是否存在并且是否过期等。
补全完整逻辑:
1 import router from './router' 2 import store from './store' 3 4 import { getToken } from './auth' 5 6 // 去除链接中的code和state 7 function delCodeandstate (to) { 8 let path = '' 9 for (const i in to.query) { 10 if (i != 'code' && i != 'state') { 11 path = path + '&' + i + '=' + to.query[i] 12 } 13 } 14 path = path == '' ? '' : path.substring(1, path.length) 15 path = path == '' ? '' : '/?' + path 16 return path 17 } 18 router.beforeEach((to, from, next) => { 19 var fullPath = to.fullPath 20 // 判断是否存在code 21 if (fullPath.includes('code')) { 22 fullPath = delCodeandstate(to) 23 } 24 const token = getToken() // 获取token 25 const redirectUrl = encodeURIComponent(`${window.location.origin}`) // 授权登陆后的回调地址,需要进行encodeURIComponent处理 26 const appId = 'ww****123' // 企业微信ID 27 const scope = 'snsapi_base' // 授权类型,snsapi_base(静默授权)或snsapi_privateinfo(手动授权) 28 const urlState = '123' // 用于防止CSRF攻击,可以是任意字符串 29 const agentId = '123***123' // 企业内应用id 30 const openUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${urlState}&agentid=${agentId}#wechat_redirect` 31 const code = to.query.code // 链接中code 32 const state = to.query.state // 链接中state 33 const whiteList = ['/login'] // 免登录白名单 34 let isCur = false // 是否免登录 35 setTimeout(() => { 36 // 判断白名单 37 for (const i of whiteList) { 38 if (to.path == i) { 39 isCur = true 40 } 41 } 42 if (isCur) { 43 next() // 白名单内不做登录判断,直接next 44 } else { 45 if (code && state && !token) { 46 // 获得授权后,不存在登录信息 47 const fd = { 48 code: code, 49 state: state 50 } 51 // 接口请求获取登录信息,根据自己逻辑配置 52 store.dispatch('WXCallback', fd).then((res) => { 53 next({ 54 path: '/' 55 }) 56 }).catch(() => { 57 }) 58 } else if (token) { 59 // 已经存在登录信息,有token,判断token是否过期 60 store.dispatch('CheckToken').then((res) => { 61 // 判断token是否过期,以及token过期后清除token的操作可以在request的拦截中进行,也可以在CheckToken中进行 62 if (res.code == 200) { 63 // token未过期,直接登录 64 next({ 65 path: '/' 66 }) 67 } else if (res.code == 401) { 68 // token已过期,重新授权登录 69 window.location.href = openUrl 70 } 71 }).catch(() => { 72 }) 73 } else { // 未登录,没有token,进行授权登录 74 window.location.href = openUrl 75 } 76 } 77 }, 0) 78 })
二、扫码授权
企业微信提供了OAuth的扫码登录授权方式,可以让企业的网站在浏览器内打开时,引导成员使用企业微信扫码登录授权,从而获取成员的身份信息,免去登录的环节。
构造独立窗口登录二维码
https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=CORPID&agentid=AGENTID&redirect_uri=REDIRECT_URI&state=STATE
代码逻辑与网页授权一直,只是授权链接不同:
1 import router from './router' 2 import store from './store' 3 4 import { getToken } from './auth' 5 6 // 去除链接中的code和state 7 function delCodeandstate (to) { 8 let path = '' 9 for (const i in to.query) { 10 if (i != 'code' && i != 'state') { 11 path = path + '&' + i + '=' + to.query[i] 12 } 13 } 14 path = path == '' ? '' : path.substring(1, path.length) 15 path = path == '' ? '' : '/?' + path 16 return path 17 } 18 router.beforeEach((to, from, next) => { 19 var fullPath = to.fullPath 20 // 判断是否存在code 21 if (fullPath.includes('code')) { 22 fullPath = delCodeandstate(to) 23 } 24 const token = getToken() // 获取token 25 const redirectUrl = encodeURIComponent(`${window.location.origin}`) // 授权登陆后的回调地址,需要进行encodeURIComponent处理 26 const appId = 'ww****123' // 企业微信ID 27 const urlState = '123' // 用于防止CSRF攻击,可以是任意字符串 28 const agentId = '123***123' // 企业内应用id 29 const openUrl = `https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=${appId}&agentid=${agentId}&redirect_uri=${redirectUrl}&state=${urlState}` 30 const code = to.query.code // 链接中code 31 const state = to.query.state // 链接中state 32 const whiteList = ['/login'] // 免登录白名单 33 let isCur = false // 是否免登录 34 setTimeout(() => { 35 // 判断白名单 36 for (const i of whiteList) { 37 if (to.path == i) { 38 isCur = true 39 } 40 } 41 if (isCur) { 42 next() // 白名单内不做登录判断,直接next 43 } else { 44 if (code && state && !token) { 45 // 获得授权后,不存在登录信息 46 const fd = { 47 code: code, 48 state: state 49 } 50 // 接口请求获取登录信息,根据自己逻辑配置 51 store.dispatch('WXCallback', fd).then((res) => { 52 next({ 53 path: '/' 54 }) 55 }).catch(() => { 56 }) 57 } else if (token) { 58 // 已经存在登录信息,有token,判断token是否过期 59 store.dispatch('CheckToken').then((res) => { 60 // 判断token是否过期,以及token过期后清除token的操作可以在request的拦截中进行,也可以在CheckToken中进行 61 if (res.code == 200) { 62 // token未过期,直接登录 63 next({ 64 path: '/' 65 }) 66 } else if (res.code == 401) { 67 // token已过期,重新授权登录 68 window.location.href = openUrl 69 } 70 }).catch(() => { 71 }) 72 } else { // 未登录,没有token,进行授权登录 73 window.location.href = openUrl 74 } 75 } 76 }, 0) 77 })
注意:静默授权和扫码授权只能获取用户基本信息,若要用户敏感信息需要手动授权。
基本信息:用户id,座机号,姓名,别名
敏感信息:手机号,性别,邮箱,企业邮箱,头像url,个人二维码,地址
好了 到此就是关于静默授权、手动授权、扫码授权的相关操作。