Skip to content

Instantly share code, notes, and snippets.

@aiyogg
Last active November 27, 2024 08:27
Show Gist options
  • Save aiyogg/67a1330b68b0aadb6f43b9f8e8185a38 to your computer and use it in GitHub Desktop.
Save aiyogg/67a1330b68b0aadb6f43b9f8e8185a38 to your computer and use it in GitHub Desktop.
Wechat Work SSO
// ==UserScript==
// @name 一键 SSO 登录
// @namespace http://tampermonkey.net/
// @version 2024-10-14
// @description 在企业微信中点击接收到 BOT 的链接后,自动完成扫码登录
// @author Chuck
// @match https://sso.exmaple-company-internal.com/login.html?*
// @match https://sso.exmaple-company-external.com/login.html?*
// @icon https://www.google.com/s2/favicons?sz=64&domain=work.weixin.qq.com
// @grant GM_xmlhttpRequest
// ==/UserScript==
const target =
new URLSearchParams(window.location.search).get('target') ??
btoa('YOUR_DEFAULT_TARGET_URL')
const service = new URLSearchParams(window.location.search).get('service') ?? 'YOUR_DEFAULT_SERVICE'
const APP_ID = 'APP_ID'
const AGENT_ID = 'AGENT_ID'
const REDIRECT_URI = 'YOUR_COMPANYS_REDIRECT_URI'
const STATE = btoa(
JSON.stringify({
target: encodeURIComponent(target),
service,
cropId: APP_ID,
wechatAppId: AGENT_ID,
upstreamCropId: null,
upstreamWechatAppId: null,
})
)
const WECHAT_WORK_KEY = 'YOUR_WECHAT_BOT_KEY'
function request(url, method = 'GET', data = null) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url,
method,
data,
headers: {
'Content-Type': 'application/json',
},
onload: (response) => resolve(response.responseText),
onerror: (error) => reject(error),
})
})
}
const redirectUri = `${REDIRECT_URI}?state=${STATE}`
;(async function () {
'use strict'
const response = await request(
`https://open.work.weixin.qq.com/wwopen/sso/qrConnect?login_type=jssdk&appid=${APP_ID}&agentid=${AGENT_ID}&redirect_uri=${redirectUri}&lang=zh&version=1.2.4`
)
try {
const settings = response.match(/window\.settings\s*=\s*(\{.*?\});/)[1]
const { key } = JSON.parse(settings)
console.log('key', key)
await request(
`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WECHAT_WORK_KEY}`,
'POST',
JSON.stringify({
msgtype: 'template_card',
template_card: {
card_type: 'text_notice',
main_title: {
title: 'SSO登录确认',
desc: '点击跳转登录确认',
},
card_action: {
type: 1,
url: `https://open.work.weixin.qq.com/wwopen/sso/confirm2?k=${key}`,
title: '跳转登录确认',
},
},
})
)
// 轮询
while (true) {
await new Promise((resolve) => setTimeout(resolve, 1000))
const res = await request(
`https://open.work.weixin.qq.com/wwopen/sso/l/qrConnect?callback=jsonpCallback&key=${key}&redirect_uri=${encodeURIComponent(
redirectUri
)}&appid=${APP_ID}&lastStatus=QRCODE_SCAN_ING&_${Date.now()}`
)
console.log(res)
const data = res.match(/jsonpCallback\((.*)\)/)[1]
const { status, auth_code } = JSON.parse(data)
if (status === 'QRCODE_SCAN_NEVER') {
console.log('扫码中')
} else if (status === 'QRCODE_SCAN_ERR') {
console.log('扫码失败')
if (window.confirm('二维码已过期,重新接收?')) {
window.location.reload()
}
} else if (status === 'QRCODE_SCAN_ING') {
console.log('等待确认登录')
} else if (status === 'QRCODE_SCAN_SUCC') {
console.log('登录成功')
console.log('auth_code', auth_code)
window.location.href = `${redirectUri}&code=${auth_code}`
break
}
}
} catch (e) {
console.log(e)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment