移除钉钉通知网页授权兜底

This commit is contained in:
chenpei 2026-07-07 13:18:07 +08:00
parent b09241975c
commit 45284c3b9f

View File

@ -4,11 +4,6 @@ import {
getAuthSessionCookieCandidates,
resolveSecureAuthCookieFromRequest,
} from '@/lib/auth-cookie'
import {
DINGTALK_DIRECT_LOGIN_SOURCE,
buildDingtalkOAuthUrl,
} from '@/lib/dingtalk-oauth'
import { getDingtalkWorkNoticeClientId } from '@/lib/dingtalk-client'
import {
getConfiguredDingtalkCorpId,
normalizeDingtalkCorpId,
@ -45,13 +40,9 @@ function stringifyForInlineScript(value: string) {
function createH5LoginPage({
redirectPath,
corpId,
clientId,
fallbackOAuthUrl,
}: {
redirectPath: string
corpId: string
clientId: string
fallbackOAuthUrl: string
}) {
return new NextResponse(
`<!doctype html>
@ -67,7 +58,6 @@ function createH5LoginPage({
h1{margin:0 0 12px;font-size:22px}
p{margin:0;color:#cbd5e1;line-height:1.7}
.spinner{width:38px;height:38px;margin:0 auto 20px;border:4px solid rgba(255,255,255,.24);border-top-color:#60a5fa;border-radius:999px;animation:spin .85s linear infinite}
a{color:#93c5fd}
@keyframes spin{to{transform:rotate(360deg)}}
</style>
</head>
@ -81,7 +71,6 @@ function createH5LoginPage({
(function () {
var target = ${stringifyForInlineScript(redirectPath)};
var corpId = ${stringifyForInlineScript(corpId)};
var fallbackOAuthUrl = ${stringifyForInlineScript(fallbackOAuthUrl)};
var started = false;
var status = document.getElementById('status');
@ -103,16 +92,6 @@ function createH5LoginPage({
}
}
function appendFallbackLink() {
if (!status) return;
status.appendChild(document.createElement('br'));
status.appendChild(document.createElement('br'));
var link = document.createElement('a');
link.href = fallbackOAuthUrl;
link.textContent = '改用网页授权登录';
status.appendChild(link);
}
function showError(message, detail) {
if (status) {
status.textContent = message + '。请返回钉钉重新打开通知,或联系管理员检查钉钉免登配置。';
@ -120,30 +99,11 @@ function createH5LoginPage({
status.appendChild(document.createElement('br'));
status.appendChild(document.createTextNode('错误详情:' + String(detail).slice(0, 180)));
}
appendFallbackLink();
}
}
function fallbackToOAuth(message, error) {
var detail = stringifyError(error);
console.log('DingTalk H5 login fallback:', message, detail || error || '');
if (status) {
status.textContent = message + '。可返回钉钉重新打开通知,或点击下方改用网页授权登录。';
if (detail) {
status.appendChild(document.createElement('br'));
status.appendChild(document.createTextNode('错误详情:' + detail.slice(0, 180)));
}
appendFallbackLink();
}
}
window.__failDingtalkLogin = showError;
function completeProfile(user) {
var userInfo = encodeURIComponent(JSON.stringify(user || {}));
window.location.replace('/complete-profile?userInfo=' + userInfo);
}
function submitCode(code) {
setStatus('已获取钉钉身份,正在创建登录状态...');
var form = document.createElement('form');
@ -161,70 +121,6 @@ function createH5LoginPage({
form.submit();
}
function resolveAuthCode(result) {
return result && (result.code || result.authCode || result.auth_code);
}
function requestAuthCodeWithFallback(dd, previousError) {
if (dd.getAuthCode) {
setStatus('正在尝试钉钉新版免登接口...');
try {
var promiseResult = dd.getAuthCode({ corpId: corpId });
if (promiseResult && typeof promiseResult.then === 'function') {
promiseResult
.then(function (result) {
var code = resolveAuthCode(result);
if (!code) {
fallbackToOAuth('钉钉新版免登接口未返回授权码', result || previousError);
return;
}
submitCode(code);
})
.catch(function (error) {
fallbackToOAuth('钉钉免登授权失败', error || previousError);
});
return;
}
var directCode = resolveAuthCode(promiseResult);
if (directCode) {
submitCode(directCode);
return;
}
} catch (error) {
fallbackToOAuth('钉钉免登授权失败', error || previousError);
return;
}
}
if (dd.requestAuthCode) {
setStatus('正在尝试钉钉备用免登接口...');
try {
dd.requestAuthCode({
corpId: corpId,
clientId: ${stringifyForInlineScript(clientId)},
onSuccess: function (result) {
var code = resolveAuthCode(result);
if (!code) {
fallbackToOAuth('钉钉备用免登接口未返回授权码', result || previousError);
return;
}
submitCode(code);
},
onFail: function (error) {
fallbackToOAuth('钉钉免登授权失败', error || previousError);
}
});
return;
} catch (error) {
fallbackToOAuth('钉钉免登授权失败', error || previousError);
return;
}
}
fallbackToOAuth('钉钉免登授权失败', previousError);
}
window.__startDingtalkLogin = function () {
if (started) return;
started = true;
@ -232,19 +128,19 @@ function createH5LoginPage({
var dd = window.dd;
if (!dd || !dd.ready || !dd.runtime || !dd.runtime.permission) {
fallbackToOAuth('当前页面未检测到钉钉客户端环境');
showError('当前页面未检测到钉钉客户端环境');
return;
}
var readyTimer = setTimeout(function () {
fallbackToOAuth('钉钉免登初始化超时');
showError('钉钉免登初始化超时');
}, 15000);
if (dd.error) {
dd.error(function (error) {
console.log('DingTalk JSAPI error:', error);
clearTimeout(readyTimer);
fallbackToOAuth('钉钉免登初始化失败', error);
showError('钉钉免登初始化失败', stringifyError(error));
});
}
@ -262,45 +158,28 @@ function createH5LoginPage({
},
onFail: function (error) {
console.log('requestAuthCode failed:', error);
requestAuthCodeWithFallback(dd, error);
showError('钉钉免登授权失败', stringifyError(error));
}
});
});
};
setStatus('正在加载钉钉免登组件...');
var scriptUrls = [
'https://g.alicdn.com/dingding/dingtalk-jsapi/3.0.12/dingtalk.open.js',
'https://g.alicdn.com/dingding/dingtalk-jsapi/3.0.39/dingtalk.open.js',
'https://g.alicdn.com/dingding/dingtalk-jsapi/3.0.36/dingtalk.open.js'
];
var scriptIndex = 0;
var loadTimer = setTimeout(function () {
if (!started) fallbackToOAuth('钉钉免登组件加载超时');
if (!started) showError('钉钉免登组件加载超时');
}, 15000);
function loadDingtalkScript() {
var script = document.createElement('script');
script.src = scriptUrls[scriptIndex];
script.onload = function () {
clearTimeout(loadTimer);
if (window.__startDingtalkLogin) window.__startDingtalkLogin();
};
script.onerror = function () {
scriptIndex += 1;
if (scriptIndex < scriptUrls.length) {
setStatus('钉钉免登组件加载失败,正在尝试备用版本...');
loadDingtalkScript();
return;
}
clearTimeout(loadTimer);
fallbackToOAuth('钉钉 JSAPI 加载失败');
};
document.head.appendChild(script);
}
loadDingtalkScript();
var script = document.createElement('script');
script.src = 'https://g.alicdn.com/dingding/dingtalk-jsapi/3.0.39/dingtalk.open.js';
script.onload = function () {
clearTimeout(loadTimer);
if (window.__startDingtalkLogin) window.__startDingtalkLogin();
};
script.onerror = function () {
clearTimeout(loadTimer);
showError('钉钉 JSAPI 加载失败');
};
document.head.appendChild(script);
})();
</script>
</body>
@ -314,6 +193,38 @@ function createH5LoginPage({
)
}
function createDingtalkOnlyPage() {
return new NextResponse(
`<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>请在钉钉内打开</title>
<style>
body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0f172a;color:#f8fafc;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
main{width:min(420px,calc(100vw - 48px));padding:32px 24px;text-align:center}
h1{margin:0 0 12px;font-size:22px}
p{margin:0;color:#cbd5e1;line-height:1.7}
</style>
</head>
<body>
<main>
<h1>请在钉钉内打开</h1>
<p>考核调研通知链接需要在钉钉客户端内确认身份。</p>
</main>
</body>
</html>`,
{
status: 403,
headers: {
'Content-Type': 'text/html; charset=utf-8',
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
},
},
)
}
function createMissingCorpIdPage() {
return new NextResponse(
`<!doctype html>
@ -354,15 +265,8 @@ export async function GET(request: NextRequest) {
return NextResponse.redirect(new URL(redirectPath, getPublicAppOrigin()))
}
const fallbackOAuthUrl = buildDingtalkOAuthUrl({
redirectPath,
callbackPath: '/api/dingtalk/callback',
clientId: getDingtalkWorkNoticeClientId(),
source: DINGTALK_DIRECT_LOGIN_SOURCE,
})
if (!isDingtalkBrowser(request)) {
return NextResponse.redirect(fallbackOAuthUrl)
return createDingtalkOnlyPage()
}
const queryCorpId =
@ -377,7 +281,5 @@ export async function GET(request: NextRequest) {
return createH5LoginPage({
redirectPath,
corpId,
clientId: getDingtalkWorkNoticeClientId(),
fallbackOAuthUrl,
})
}