feat(login): support /login?sso=xxx to auto redirect to SSO provider - #2249
feat(login): support /login?sso=xxx to auto redirect to SSO provider#2249710leo wants to merge 1 commit into
Conversation
Allow a link to jump straight to the configured third-party login instead of requiring the user to click the SSO link on the login page. - accepted values: oidc / cas / oauth (oauth2) / custom / dingtalk / feishu, case-insensitive; unknown values fall back to the login form - shows a loading mask while redirecting, and restores the form with a warning when the provider has no redirect URL configured - `?admin` still wins, so /login?admin&sso=oidc keeps local login
📝 WalkthroughWalkthroughThe login page now reads the ChangesAutomatic SSO redirection
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant LoginPage
participant SSOURLGetter
participant Browser
LoginPage->>SSOURLGetter: Resolve provider redirect URL
SSOURLGetter-->>LoginPage: Return redirect URL and optional CAS state
LoginPage->>Browser: Store CAS state when present
LoginPage->>Browser: Navigate to redirect URL
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/pages/login/index.tsx (1)
66-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace
Promise<any>with a redirect response type.
anyprevents TypeScript from checking the string and CAS object shapes inres.dat. Define an explicit union or interface for these responses.As per coding guidelines, “avoid any.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/login/index.tsx` at line 66, Replace the Promise<any> return type in SSO_REDIRECT_GETTERS with an explicit redirect response type covering the supported string and CAS object shapes returned in res.dat, so TypeScript validates both forms without using any.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/login/index.tsx`:
- Around line 127-129: Update the SSO redirect request’s catch handler to both
reset ssoRedirecting and display the existing sso_no_url warning when redirect
resolution fails. Reuse the component’s established warning/notification
mechanism and preserve the form-restoration behavior.
- Around line 82-85: Update the SSO redirect effect around ssoWay and
SSO_REDIRECT_GETTERS to depend on both ssoWay and redirect rather than only the
initial values. Set ssoRedirecting to false when no recognized provider exists,
and guard asynchronous redirect results with a cleanup-stale flag so outdated
promises cannot update state after query changes or unmount.
---
Nitpick comments:
In `@src/pages/login/index.tsx`:
- Line 66: Replace the Promise<any> return type in SSO_REDIRECT_GETTERS with an
explicit redirect response type covering the supported string and CAS object
shapes returned in res.dat, so TypeScript validates both forms without using
any.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: affc8265-629d-43be-962f-279dfa6a20fe
📒 Files selected for processing (1)
src/pages/login/index.tsx
| const searchParams = new URLSearchParams(location.search); | ||
| // 带 ?admin 表示要用本地账号登录,此时不自动跳转,与 Plus 侧全局自动跳转的约定保持一致 | ||
| const ssoWay = searchParams.has('admin') ? '' : (searchParams.get('sso') || '').toLowerCase(); | ||
| const [ssoRedirecting, setSsoRedirecting] = useState(!!SSO_REDIRECT_GETTERS[ssoWay]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- file outline ---'
ast-grep outline src/pages/login/index.tsx
printf '%s\n' '--- relevant source ---'
sed -n '1,180p' src/pages/login/index.tsx
printf '%s\n' '--- focused diff ---'
git diff -- src/pages/login/index.tsx
printf '%s\n' '--- related symbols ---'
rg -n -C 3 'SSO_REDIRECT_GETTERS|ssoWay|ssoRedirecting|location\.search|redirect' src/pages/login/index.tsxRepository: n9e/fe
Length of output: 10385
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- effect and render sections ---'
sed -n '76,138p' src/pages/login/index.tsx
sed -n '185,205p' src/pages/login/index.tsx
printf '%s\n' '--- login route usage ---'
rg -n -C 3 'pages/login|Login\b|path=.*login|/login' src --glob '*.{ts,tsx}'
printf '%s\n' '--- redirect service signatures ---'
rg -n -C 4 'export (async )?function getRedirect|const getRedirect|function getRedirect' src
printf '%s\n' '--- React/router versions ---'
rg -n '"(react|react-router|react-router-dom)"' package.json */package.json 2>/dev/null || true
printf '%s\n' '--- standalone lifecycle probe ---'
node - <<'JS'
const getters = { oidc: () => Promise.resolve({ dat: 'oidc-url' }) };
let state = false;
let currentQuery = { sso: 'oidc', redirect: '/first' };
function render(query) {
const ssoWay = query.sso || '';
const redirect = query.redirect || '';
const effect = () => {
const getter = getters[ssoWay];
if (!getter) return;
getter(redirect).then((res) => {
if (res.dat) {
console.log(`redirect=${res.dat}, requested=${redirect}`);
}
});
};
return { effect, initialLoading: !!getters[ssoWay] };
}
const first = render(currentQuery);
state = first.initialLoading;
currentQuery = { sso: 'oidc', redirect: '/second' };
const second = render(currentQuery);
console.log(`state-after-query-change=${state}`);
first.effect(); // Models an effect with [] retaining its first render's closure.
console.log(`new-render-effect-created=${typeof second.effect === 'function'}`);
JSRepository: n9e/fe
Length of output: 28205
React to later login query changes.
The empty dependency array captures the initial ssoWay and redirect. Add both dependencies, synchronize ssoRedirecting for recognized and unrecognized providers, and ignore stale promise results during cleanup.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/login/index.tsx` around lines 82 - 85, Update the SSO redirect
effect around ssoWay and SSO_REDIRECT_GETTERS to depend on both ssoWay and
redirect rather than only the initial values. Set ssoRedirecting to false when
no recognized provider exists, and guard asynchronous redirect results with a
cleanup-stale flag so outdated promises cannot update state after query changes
or unmount.
| .catch(() => { | ||
| setSsoRedirecting(false); | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Show the SSO failure warning on request errors.
This path restores the form but does not display sso_no_url. The PR requires the existing message when redirect resolution fails.
Proposed fix
.catch(() => {
+ message.warning(t('sso_no_url', { name: ssoWay }));
setSsoRedirecting(false);
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .catch(() => { | |
| setSsoRedirecting(false); | |
| }); | |
| .catch(() => { | |
| message.warning(t('sso_no_url', { name: ssoWay })); | |
| setSsoRedirecting(false); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/login/index.tsx` around lines 127 - 129, Update the SSO redirect
request’s catch handler to both reset ssoRedirecting and display the existing
sso_no_url warning when redirect resolution fails. Reuse the component’s
established warning/notification mechanism and preserve the form-restoration
behavior.
背景
登录页目前只能手动点击「其他登录方式」里的 SSO 链接。有些场景(内部门户跳转、书签、告警通知里的链接)希望直接落到第三方登录,省掉这一次点击。
Pro 版虽然有
global_sso_way的全局自动跳转,但它由后端配置决定跳哪个,前端无法按链接指定。改动
登录页新增
ssoURL 参数,例如/login?sso=oidc,等价于自动点了对应的 SSO 链接。oidc/cas/oauth(兼容oauth2)/custom/dingtalk/feishu,大小写不敏感sso_no_url提示,不会卡在转圈redirect参数照常透传给 SSO 接口?admin仍然是「用本地账号登录」的逃生口,/login?admin&sso=oidc不跳转实现为纯增量,复用已有的
getRedirectURL*service,未改动原有的六个 SSO 链接,未新增 i18n key。配套 PR(Pro):URL 上显式指定
sso时,useSsoWay不再按global_sso_way跳转,避免两处抢着写window.location.href。验证
用 Playwright 对社区版构建(
plus:走 PlusPlaceholder)做的端到端验证:/login正常渲染、无 JS 运行时错误?sso=oidc未配置时还原表单 + 提示?sso=oidc跳转前展示遮罩、不闪表单?sso=oidc已配置时自动跳转?sso=cas自动跳转且写入CAS_state?sso=OAuth2大小写与别名兼容?sso=oidc&redirect=/targets透传 redirect?sso=garbage展示表单、不发跳转请求?sso=oidc&admin保留本地表单、不跳转Summary by CodeRabbit