fix(msa): 微软登录默认走设备码,浏览器流降级为可选加速路
官方产物上点「微软登录」必失败:GUI 只接了授权码流(随机端口回环回调),而 Azure 应用 注册当初是为 device-code 建的,重定向 URI 一项都没登记,于是授权端点当场回 `invalid_request: ... 'redirect_uri' is not valid`,浏览器里只剩一张 AAD 原始错误页, 启动器干等 5 分钟超时。设备码流本身是好的(CLI `accounts add msa` 一直能用)。 - core:新增 `preflight`(回环重定向 URI 注册预检)与 `login`(浏览器优先 + 自动回退设备码)。 预检拿「即将使用的 redirect_uri」(端口不参与匹配,微软官方文档 *Localhost exceptions* 原文已引进模块文档)先问一次授权端点;没登记 / 问不出来就地跳过,**一个监听口都不开**。 预检通过才真绑端口走授权码;授权码失败(超时/被拒/绑不上)自动回退设备码并带上结构化 原因码;用户取消(`Canceled`)原样上抛,不偷偷换流。设备码是默认,零监听口。 - presenter:`start_login` = 设备码(默认);`start_browser_login` = 浏览器优先 + 回退, 回退原因码写进 `DeviceLoginView.browser_note`(原文只进日志)。 - i18n:三条回退文案(含「怎么修:把 http://localhost/auth 加进重定向 URI,端口不参与匹配」)。 - app-iced:登录面板主按钮改成设备码、浏览器降级为次按钮;重登也走设备码;设备码面板与失败 面板都能画回退说明。倒计时文案改由视图模型持有(借用渲染),顺带修掉中文倒计时整行不显示。 - 守卫(都能变红):①授权端点回 invalid_request 时确实回退设备码且原因是结构化码; ②未登记回环 / 默认设备码路 `listeners_opened == 0`;③回环登记了仍能走授权码(不焊死加速路); ④用户取消不被偷偷换流;⑤client id 仍只能构建期注入(扫 `auth/microsoft/` 源码无 UUID 字面量)。
This commit is contained in:
1 parent
329c529bea
commit
f82bd395f8
23 files changed
+1373
-131
No files matched your search
@@ -33,7 +33,7 @@ fn account(name: &str, kind: AccountKind, active: bool) -> AccountView {
|
||||
}
|
||||
}
|
||||
|
||||
fn build(state: &AppState, form: &Form) -> Page {
|
||||
pub(super) fn build(state: &AppState, form: &Form) -> Page {
|
||||
// 断言口径是英文界面(app 钉死 `Lang::En`):英文目录下「视图里有中文」=「后端原文上屏了」。
|
||||
// 宽度取验收窗口 1180(r2 起 `Page` 记中栏可用宽)。
|
||||
Page::build(state, form, &mut Cache::default(), Lang::En, 1180.0)
|
||||
@@ -212,12 +212,15 @@ fn the_device_code_panel_shows_a_countdown_and_expires() {
|
||||
match &page.device {
|
||||
DevicePanel::Code {
|
||||
code,
|
||||
remaining,
|
||||
countdown,
|
||||
expired,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(code, "ABCD-EFGH");
|
||||
assert_eq!(*remaining, Some(900));
|
||||
assert!(
|
||||
countdown.contains("15:00"),
|
||||
"倒计时要画成 mm:ss:{countdown}"
|
||||
);
|
||||
assert!(!expired);
|
||||
}
|
||||
other => panic!("等待态应该是设备码面板,实际 {other:?}"),
|
||||
@@ -232,10 +235,10 @@ fn the_device_code_panel_shows_a_countdown_and_expires() {
|
||||
let page = build(&state, &Form::new());
|
||||
match &page.device {
|
||||
DevicePanel::Code {
|
||||
remaining, expired, ..
|
||||
countdown, expired, ..
|
||||
} => {
|
||||
assert_eq!(*remaining, Some(0));
|
||||
assert!(*expired, "过期必须被标出来(面板要画「已过期,重试」)");
|
||||
assert!(!countdown.is_empty(), "过期也要有一句人话,不是空行");
|
||||
}
|
||||
other => panic!("过期态仍是设备码面板,实际 {other:?}"),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user