feat(auth): 支持自定义 Builder ID Start URL 并添加相关国际化

为 Kiro OAuth 添加 Builder ID Start URL 的可配置选项,优先使用前端传入的值
添加相关国际化文本和 UI 控件,允许用户自定义或重新生成 Start URL
同时支持通过 options.authMethod 参数指定认证方法
This commit is contained in:
hex2077 2026-01-13 19:09:17 +08:00
parent 817c25267b
commit 281d242466
3 changed files with 56 additions and 3 deletions

View file

@ -665,7 +665,7 @@ export async function handleQwenOAuth(currentConfig, options = {}) {
* @returns {Promise<Object>} 返回授权URL和相关信息
*/
export async function handleKiroOAuth(currentConfig, options = {}) {
const method = options.method || 'google'; // 默认使用 Google
const method = options.method || options.authMethod || 'google'; // 默认使用 Google,同时支持 authMethod 参数
console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Starting OAuth with method: ${method}`);
@ -740,6 +740,10 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
}
}
// 获取 Builder ID Start URL优先使用前端传入的值否则使用默认值
const builderIDStartURL = options.builderIDStartURL || KIRO_OAUTH_CONFIG.builderIDStartURL;
console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Using Builder ID Start URL: ${builderIDStartURL}`);
// 1. 注册 OIDC 客户端
const regResponse = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/client/register`, {
method: 'POST',
@ -771,7 +775,7 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) {
body: JSON.stringify({
clientId: regData.clientId,
clientSecret: regData.clientSecret,
startUrl: KIRO_OAUTH_CONFIG.builderIDStartURL
startUrl: builderIDStartURL
})
}, 'claude-kiro-oauth');

View file

@ -177,6 +177,8 @@ const translations = {
'oauth.kiro.importError': '导入出错',
'oauth.kiro.duplicateToken': '重复凭据 - 此 refreshToken 已存在',
'oauth.kiro.duplicateCredentials': '该凭据已存在,请勿重复导入',
'oauth.kiro.builderIDStartURL': 'Builder ID Start URL',
'oauth.kiro.builderIDStartURLHint': '如果您使用 AWS IAM Identity Center请输入您的 Start URL',
'oauth.iflow.step1': '点击下方按钮在浏览器中打开 iFlow 授权页面',
'oauth.iflow.step2': '使用您的 iFlow 账号登录并授权',
'oauth.iflow.step3': '授权完成后,系统会自动获取 API Key',
@ -527,6 +529,7 @@ const translations = {
'common.loading': '加载中...',
'common.upload': '上传',
'common.generate': '生成',
'common.optional': '可选',
'common.found': '已找到',
'common.missing': '缺失',
'common.search': '搜索',
@ -732,6 +735,8 @@ const translations = {
'oauth.kiro.importError': 'Import error',
'oauth.kiro.duplicateToken': 'Duplicate - this refreshToken already exists',
'oauth.kiro.duplicateCredentials': 'This credential already exists, please do not import duplicates',
'oauth.kiro.builderIDStartURL': 'Builder ID Start URL',
'oauth.kiro.builderIDStartURLHint': 'If you use AWS IAM Identity Center, enter your Start URL',
'oauth.iflow.step1': 'Click the button below to open the iFlow authorization page',
'oauth.iflow.step2': 'Log in with your iFlow account and authorize',
'oauth.iflow.step3': 'After authorization, the system will automatically fetch the API Key',
@ -1085,6 +1090,7 @@ const translations = {
'common.loading': 'Loading...',
'common.upload': 'Upload',
'common.generate': 'Generate',
'common.optional': 'Optional',
'common.found': 'Found',
'common.missing': 'Missing',
'common.search': 'Search',

View file

@ -680,7 +680,7 @@ function showKiroAuthMethodSelector(providerType) {
modal.style.display = 'flex';
modal.innerHTML = `
<div class="modal-content" style="max-width: 500px;">
<div class="modal-content" style="max-width: 550px;">
<div class="modal-header">
<h3><i class="fas fa-key"></i> <span data-i18n="oauth.kiro.selectMethod">${t('oauth.kiro.selectMethod')}</span></h3>
<button class="modal-close">&times;</button>
@ -1727,6 +1727,29 @@ function showAuthModal(authUrl, authInfo) {
}
</div>
<p style="margin: 8px 0 0 0; font-size: 0.85rem; color: #92400e;" data-i18n="oauth.modal.portNote">${t('oauth.modal.portNote')}</p>
${(authInfo.provider === 'claude-kiro-oauth' && authInfo.authMethod === 'builder-id') ? `
<div class="builder-id-url-section" style="margin-top: 12px; padding-top: 12px; border-top: 1px dashed #fcd34d;">
<label style="display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 13px; font-weight: 600; color: #92400e;">
<i class="fas fa-link"></i>
<span data-i18n="oauth.kiro.builderIDStartURL">${t('oauth.kiro.builderIDStartURL') || 'Builder ID Start URL'}</span>
<span style="font-weight: normal; color: #b45309;">(${t('common.optional') || '可选'})</span>
</label>
<div style="display: flex; align-items: center; gap: 4px;">
<input type="text" class="builder-id-start-url-input"
value="${authInfo.builderIDStartURL || 'https://view.awsapps.com/start'}"
placeholder="https://view.awsapps.com/start"
style="flex: 1; padding: 6px 10px; border: 1px solid #fcd34d; border-radius: 4px; font-size: 13px; color: #92400e; background: white;"
/>
<button class="regenerate-builder-id-btn" title="${t('common.generate')}" style="background: none; border: 1px solid #d97706; border-radius: 4px; cursor: pointer; color: #d97706; padding: 4px 8px;">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<p style="margin: 6px 0 0 0; font-size: 0.75rem; color: #b45309;">
<i class="fas fa-info-circle"></i>
<span data-i18n="oauth.kiro.builderIDStartURLHint">${t('oauth.kiro.builderIDStartURLHint') || '如果您使用 AWS IAM Identity Center请输入您的 Start URL'}</span>
</p>
</div>
` : ''}
</div>
${instructionsHtml}
<div class="auth-url-section">
@ -1780,6 +1803,26 @@ function showAuthModal(authUrl, authInfo) {
};
}
// Builder ID Start URL 重新生成按钮事件
const regenerateBuilderIdBtn = modal.querySelector('.regenerate-builder-id-btn');
if (regenerateBuilderIdBtn) {
regenerateBuilderIdBtn.onclick = async () => {
const builderIdStartUrl = modal.querySelector('.builder-id-start-url-input').value.trim();
modal.remove();
// 构造重新请求的参数
const options = {
...authInfo,
builderIDStartURL: builderIdStartUrl || 'https://view.awsapps.com/start'
};
// 移除不需要传递回后端的字段
delete options.provider;
delete options.redirectUri;
delete options.callbackPort;
await executeGenerateAuthUrl(authInfo.provider, options);
};
}
// 复制链接按钮
const copyBtn = modal.querySelector('.copy-btn');
copyBtn.addEventListener('click', () => {