<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cloudpods –
认证</title><link>/docs/zh/tags/%E8%AE%A4%E8%AF%81/</link><description>Recent content in 认证 on Cloudpods</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><atom:link href="/docs/zh/tags/%E8%AE%A4%E8%AF%81/index.xml" rel="self" type="application/rss+xml"/><item><title>Docs: 登录测试用例</title><link>/docs/zh/docs/web_ui/testcase/login/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/docs/zh/docs/web_ui/testcase/login/</guid><description>
&lt;h2 id="适用范围"&gt;适用范围&lt;/h2&gt;
&lt;p&gt;覆盖云联壹云 Web 控制台的登录、登录安全策略、退出与会话管理。涉及的产品功能参见：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="../../../practice/login"&gt;登录界面&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../intro/usercenter/userinfor"&gt;用户信息&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../intro/usercenter/signout"&gt;退出系统&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../intro/ui/view"&gt;切换视图&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../auth-security/authentication/authentication-system/systemuser"&gt;用户管理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../auth-security/security/security-alert/securityalert"&gt;安全告警&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="环境与账号"&gt;环境与账号&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;地址&lt;/td&gt;
&lt;td&gt;&lt;a href="https://test.yunion.io" target="_blank" rel="noopener noreferrer"&gt;https://test.yunion.io&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;账号&lt;/td&gt;
&lt;td&gt;cloudadmin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;密码&lt;/td&gt;
&lt;td&gt;cloudadmin@test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;域&lt;/td&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;登录页元素（以实际界面为准）：账号登录/手机号登录页签、用户名输入框、密码输入框、登录按钮、图形验证码（按策略出现）、指定登录域入口、忘记密码、第三方/CAS 登录入口。&lt;/p&gt;
&lt;h2 id="用例总览"&gt;用例总览&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;编号&lt;/th&gt;
&lt;th&gt;用例名称&lt;/th&gt;
&lt;th&gt;优先级&lt;/th&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-001&lt;/td&gt;
&lt;td&gt;使用正确的用户名和密码登录&lt;/td&gt;
&lt;td&gt;P0&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-002&lt;/td&gt;
&lt;td&gt;使用错误的密码登录&lt;/td&gt;
&lt;td&gt;P0&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-003&lt;/td&gt;
&lt;td&gt;使用不存在的用户名登录&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-004&lt;/td&gt;
&lt;td&gt;用户名或密码为空提交&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;校验&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-005&lt;/td&gt;
&lt;td&gt;指定登录域登录&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-006&lt;/td&gt;
&lt;td&gt;域与用户不匹配时登录失败&lt;/td&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-007&lt;/td&gt;
&lt;td&gt;连续输错密码后出现图形验证码&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;安全&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-008&lt;/td&gt;
&lt;td&gt;连续输错密码超过上限锁定账户并产生安全告警&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;安全&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-009&lt;/td&gt;
&lt;td&gt;禁用&amp;quot;控制台登录&amp;quot;的用户无法登录&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-010&lt;/td&gt;
&lt;td&gt;被禁用的用户无法登录&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-011&lt;/td&gt;
&lt;td&gt;启用 MFA 的用户登录&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-012&lt;/td&gt;
&lt;td&gt;密码已过期的用户无法登录&lt;/td&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;反向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-013&lt;/td&gt;
&lt;td&gt;登录后落地视图正确&lt;/td&gt;
&lt;td&gt;P0&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-014&lt;/td&gt;
&lt;td&gt;退出登录后会话失效&lt;/td&gt;
&lt;td&gt;P0&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-015&lt;/td&gt;
&lt;td&gt;未登录直接访问内页跳转登录页&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;安全&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-016&lt;/td&gt;
&lt;td&gt;切换登录界面语言&lt;/td&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-017&lt;/td&gt;
&lt;td&gt;认证源（LDAP）用户登录&lt;/td&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;正向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TC-LOGIN-018&lt;/td&gt;
&lt;td&gt;登录会话有效期&lt;/td&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;安全&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-001-使用正确的用户名和密码登录"&gt;TC-LOGIN-001 使用正确的用户名和密码登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P0&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：cloudadmin 账号已启用且允许控制台登录。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;浏览器打开 &lt;a href="https://test.yunion.io" target="_blank" rel="noopener noreferrer"&gt;https://test.yunion.io&lt;/a&gt; 。&lt;/li&gt;
&lt;li&gt;在&amp;quot;账号登录&amp;quot;页签中输入用户名 &lt;code&gt;cloudadmin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;输入密码 &lt;code&gt;cloudadmin@test&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;提交后界面提示&amp;quot;正在登录，请稍候&amp;quot;一类的过渡状态。&lt;/li&gt;
&lt;li&gt;登录成功，跳转到控制面板页面，右上角显示当前用户。&lt;/li&gt;
&lt;li&gt;顶部区域显示视图切换入口，当前视图为&lt;strong&gt;管理后台视图&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;浏览器中生成登录凭证（&lt;code&gt;yunionauth&lt;/code&gt;）及 &lt;code&gt;scope&lt;/code&gt;、&lt;code&gt;domain&lt;/code&gt;、&lt;code&gt;tenant&lt;/code&gt; 等 Cookie。&lt;/li&gt;
&lt;li&gt;再次输入地址访问控制台，无需重新登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;实测结果&lt;/strong&gt;：通过（接口层已验证，见附录 B）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-002-使用错误的密码登录"&gt;TC-LOGIN-002 使用错误的密码登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P0&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：同 TC-LOGIN-001。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页。&lt;/li&gt;
&lt;li&gt;输入用户名 &lt;code&gt;cloudadmin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;输入错误密码 &lt;code&gt;wrongpass123&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录失败，停留在登录页。&lt;/li&gt;
&lt;li&gt;页面提示&amp;quot;用户名或密码错误&amp;quot;（接口返回 &lt;code&gt;incorrect username or password&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;密码输入框被清空或以密文形式保留，不出现明文回显。&lt;/li&gt;
&lt;li&gt;未生成有效登录凭证，无法进入控制台。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;实测结果&lt;/strong&gt;：通过。接口返回 HTTP 401，响应体为 &lt;code&gt;{&amp;quot;class&amp;quot;:&amp;quot;IncorrectUsernameOrPassword&amp;quot;,&amp;quot;code&amp;quot;:401,&amp;quot;details&amp;quot;:&amp;quot;incorrect username or password&amp;quot;}&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-003-使用不存在的用户名登录"&gt;TC-LOGIN-003 使用不存在的用户名登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页。&lt;/li&gt;
&lt;li&gt;输入用户名 &lt;code&gt;no_such_user_9999&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;输入任意密码。&lt;/li&gt;
&lt;li&gt;单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录失败。&lt;/li&gt;
&lt;li&gt;提示信息与 TC-LOGIN-002 &lt;strong&gt;一致&lt;/strong&gt;，不区分&amp;quot;用户名不存在&amp;quot;与&amp;quot;密码错误&amp;quot;，避免泄露账号是否存在。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-004-用户名或密码为空提交"&gt;TC-LOGIN-004 用户名或密码为空提交&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页，用户名与密码均留空，单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;li&gt;仅填写用户名，密码留空，单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;li&gt;仅填写密码，用户名留空，单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;三种情况均不发起登录请求，直接停留在当前页。&lt;/li&gt;
&lt;li&gt;对应的输入框下方出现校验提示&amp;quot;请输入用户名&amp;quot;/&amp;ldquo;请输入密码&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;输入框标红或有明显错误态。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-005-指定登录域登录"&gt;TC-LOGIN-005 指定登录域登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：Default 域存在已启用且允许控制台登录的用户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页，单击&amp;quot;指定登录域&amp;quot;入口。&lt;/li&gt;
&lt;li&gt;在域列表中选择 &lt;code&gt;Default&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;输入用户名 &lt;code&gt;cloudadmin&lt;/code&gt;、密码 &lt;code&gt;cloudadmin@test&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;li&gt;在控制台右上角用户菜单中重新打开登录域设置，单击&amp;quot;重置登录域&amp;quot;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;指定登录域后界面显示&amp;quot;当前登录域：Default&amp;quot;。&lt;/li&gt;
&lt;li&gt;登录成功，进入控制台。&lt;/li&gt;
&lt;li&gt;重置登录域后，登录页恢复为平台级登录，不预选任何域。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-006-域与用户不匹配时登录失败"&gt;TC-LOGIN-006 域与用户不匹配时登录失败&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P2&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：存在一个 cloudadmin 未加入的域（如新建域 &lt;code&gt;testdomain&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页，单击&amp;quot;指定登录域&amp;quot;，选择 cloudadmin 未加入的域。&lt;/li&gt;
&lt;li&gt;输入用户名 &lt;code&gt;cloudadmin&lt;/code&gt;、密码 &lt;code&gt;cloudadmin@test&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;单击&amp;quot;登录&amp;quot;按钮。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录失败，提示用户名或密码错误。&lt;/li&gt;
&lt;li&gt;不发生跨域越权登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-007-连续输错密码后出现图形验证码"&gt;TC-LOGIN-007 连续输错密码后出现图形验证码&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：确认平台已配置密码错误次数阈值（keystone 服务参数 &lt;code&gt;password_error_lock_count&lt;/code&gt;，默认 0 表示不锁定）。&lt;strong&gt;该用例会占用 cloudadmin 的错误次数，执行前请与管理员确认阈值，避免锁定账号。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 cloudadmin 与错误密码连续登录，直到界面出现验证码输入框。&lt;/li&gt;
&lt;li&gt;记录触发验证码所需的失败次数。&lt;/li&gt;
&lt;li&gt;在验证码输入框中输入错误验证码，单击&amp;quot;登录&amp;quot;。&lt;/li&gt;
&lt;li&gt;输入正确验证码后提交。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;达到阈值后登录页出现图形验证码输入框，且验证码图片可刷新。&lt;/li&gt;
&lt;li&gt;验证码错误时提示&amp;quot;请输入有效的验证码&amp;quot;/&amp;ldquo;验证码错误&amp;rdquo;，登录被拒绝。&lt;/li&gt;
&lt;li&gt;验证码正确且密码正确时登录成功。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;备注&lt;/strong&gt;：若平台未开启验证码策略，本用例标记为&amp;quot;不适用&amp;quot;并记录平台配置值。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-008-连续输错密码超过上限锁定账户并产生安全告警"&gt;TC-LOGIN-008 连续输错密码超过上限锁定账户并产生安全告警&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：&lt;code&gt;password_error_lock_count&lt;/code&gt; 已配置为大于 0 的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 cloudadmin 与错误密码连续登录，超过配置的阈值。&lt;/li&gt;
&lt;li&gt;尝试使用&lt;strong&gt;正确&lt;/strong&gt;密码登录。&lt;/li&gt;
&lt;li&gt;使用管理员账号登录，查看安全告警列表。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;超过阈值后账户被锁定，即使输入正确密码也无法登录，提示账户已锁定。&lt;/li&gt;
&lt;li&gt;安全告警页面生成一条&amp;quot;异常登录&amp;quot;告警记录。&lt;/li&gt;
&lt;li&gt;告警同时发送给被锁定用户本人、其所在域的域管理员和系统管理员。&lt;/li&gt;
&lt;li&gt;解除锁定后，使用正确密码可正常登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;备注&lt;/strong&gt;：&lt;strong&gt;该用例会锁定 cloudadmin 账号&lt;/strong&gt;，请勿在生产或共享环境执行；执行前确认可解锁。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-009-禁用控制台登录的用户无法登录"&gt;TC-LOGIN-009 禁用&amp;quot;控制台登录&amp;quot;的用户无法登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：准备一个已启用但**关闭&amp;quot;登录控制台&amp;quot;**的本地用户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用管理员在用户管理中新建用户，关闭&amp;quot;登录控制台&amp;quot;。&lt;/li&gt;
&lt;li&gt;退出当前登录，使用该用户登录控制台。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录被拒绝，提示无控制台登录权限或用户名密码错误。&lt;/li&gt;
&lt;li&gt;该用户仍可通过 API 等方式访问（如平台允许），但无法登录控制台。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-010-被禁用的用户无法登录"&gt;TC-LOGIN-010 被禁用的用户无法登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：准备一个处于禁用状态的用户，且该用户当前已在线。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用该用户登录控制台并保持在线。&lt;/li&gt;
&lt;li&gt;使用管理员在用户管理中禁用该用户。&lt;/li&gt;
&lt;li&gt;该用户继续操作控制台页面。&lt;/li&gt;
&lt;li&gt;该用户退出后再次登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;禁用操作&lt;strong&gt;不会&lt;/strong&gt;强制在线用户立即退出。&lt;/li&gt;
&lt;li&gt;用户退出后再次登录失败，提示用户已禁用。&lt;/li&gt;
&lt;li&gt;使用被禁用用户的正确密码登录同样失败。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-011-启用-mfa-的用户登录"&gt;TC-LOGIN-011 启用 MFA 的用户登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：全局配置已启用双因子认证，且目标用户已开启 MFA 并完成凭证绑定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用已开启 MFA 的用户登录，输入正确的用户名和密码。&lt;/li&gt;
&lt;li&gt;在出现的登录保护页面中输入 6 位安全码。&lt;/li&gt;
&lt;li&gt;使用错误安全码提交一次。&lt;/li&gt;
&lt;li&gt;使用正确安全码提交。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;密码校验通过后不直接进入控制台，而是要求输入 6 位安全码。&lt;/li&gt;
&lt;li&gt;错误安全码提示&amp;quot;安全码不正确，请重新输入&amp;quot;，无法进入控制台。&lt;/li&gt;
&lt;li&gt;正确安全码提交后成功进入控制台。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;备注&lt;/strong&gt;：test.yunion.io 上 cloudadmin 当前&lt;strong&gt;未开启&lt;/strong&gt; MFA（登录凭证中 &lt;code&gt;totp_on=false&lt;/code&gt;），执行本用例需先准备一个开启 MFA 的用户；若全局双因子认证未启用，用户侧 MFA 开关不生效。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-012-密码已过期的用户无法登录"&gt;TC-LOGIN-012 密码已过期的用户无法登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P2&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：存在密码已过期的用户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用密码已过期的用户登录。&lt;/li&gt;
&lt;li&gt;使用密码还有 7 天过期的用户登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;密码已过期的用户&lt;strong&gt;无法&lt;/strong&gt;登录系统。&lt;/li&gt;
&lt;li&gt;密码还有 7 天过期的用户可正常登录，登录后提示密码即将过期，建议尽快修改。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-013-登录后落地视图正确"&gt;TC-LOGIN-013 登录后落地视图正确&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P0&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：cloudadmin 为 Default 域 system 项目的 admin 角色。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 cloudadmin 登录。&lt;/li&gt;
&lt;li&gt;查看顶部区域视图切换入口。&lt;/li&gt;
&lt;li&gt;依次切换到域管理后台视图、项目视图，再切回管理后台视图。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;默认落地&lt;strong&gt;管理后台视图&lt;/strong&gt;，可看到系统级资源。&lt;/li&gt;
&lt;li&gt;视图切换入口正常展示，切换后左侧导航菜单随视图变化。&lt;/li&gt;
&lt;li&gt;域管理后台视图要求平台已开启三级权限；未开启时该视图不出现。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-014-退出登录后会话失效"&gt;TC-LOGIN-014 退出登录后会话失效&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P0&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录控制台，记录当前地址。&lt;/li&gt;
&lt;li&gt;单击右上角用户图标，选择&amp;quot;退出&amp;quot;。&lt;/li&gt;
&lt;li&gt;使用浏览器后退按钮回到退出前的页面。&lt;/li&gt;
&lt;li&gt;直接粘贴退出前的内页地址访问。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;退出后跳转到登录页。&lt;/li&gt;
&lt;li&gt;后退或直接访问内页均被重定向到登录页，不展示业务数据。&lt;/li&gt;
&lt;li&gt;浏览器中的登录凭证已失效。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;第三方认证源（如 CAS）用户退出后，若认证服务器侧会话未销毁，可能被自动重新登录，属于认证源行为，需单独确认。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-015-未登录直接访问内页跳转登录页"&gt;TC-LOGIN-015 未登录直接访问内页跳转登录页&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;清除浏览器 Cookie 或使用无痕窗口。&lt;/li&gt;
&lt;li&gt;直接访问内页地址，如 &lt;code&gt;/vminstance&lt;/code&gt; 一类的资源列表地址。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;请求被拦截，跳转到登录页。&lt;/li&gt;
&lt;li&gt;登录成功后跳转回原访问的内页地址（如平台支持回跳）。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-016-切换登录界面语言"&gt;TC-LOGIN-016 切换登录界面语言&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P2&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开登录页，将界面语言切换为英文。&lt;/li&gt;
&lt;li&gt;切换回简体中文。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录页文案随语言切换，登录按钮、输入框提示、错误提示均为目标语言。&lt;/li&gt;
&lt;li&gt;切换语言不影响已输入的用户名和密码。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-017-认证源ldap用户登录"&gt;TC-LOGIN-017 认证源（LDAP）用户登录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P2&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前置条件&lt;/strong&gt;：平台已配置并启用 LDAP 认证源，且已同步用户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在登录页选择对应的认证源（如&amp;quot;指定登录域&amp;quot;中选择认证源对应的域）。&lt;/li&gt;
&lt;li&gt;输入 LDAP 用户的用户名和密码登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;认证源用户可正常登录控制台。&lt;/li&gt;
&lt;li&gt;用户管理中被标记为 LDAP 认证源的用户，&lt;strong&gt;不支持&lt;/strong&gt;在平台侧重置密码。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="tc-login-018-登录会话有效期"&gt;TC-LOGIN-018 登录会话有效期&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;：P2&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录控制台，查看登录凭证 Cookie 的过期时间。&lt;/li&gt;
&lt;li&gt;保持页面空闲超过凭证有效期后，再操作页面或访问内页。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;预期结果&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录凭证有效期默认为 24 小时（&lt;code&gt;Max-Age=86399&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;凭证过期后，操作页面或访问内页被重定向到登录页，需重新登录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;实测结果&lt;/strong&gt;：通过。实测登录响应中 &lt;code&gt;yunionauth&lt;/code&gt;、&lt;code&gt;scope&lt;/code&gt;、&lt;code&gt;domain&lt;/code&gt;、&lt;code&gt;tenant&lt;/code&gt; 四个 Cookie 的 &lt;code&gt;Max-Age&lt;/code&gt; 均为 86399 秒。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="附录-a接口层验证脚本"&gt;附录 A：接口层验证脚本&lt;/h2&gt;
&lt;p&gt;登录相关的界面行为可用登录接口快速回归。以下脚本对 &lt;a href="https://test.yunion.io" target="_blank" rel="noopener noreferrer"&gt;https://test.yunion.io&lt;/a&gt; 执行接口级验证，可直接复制运行（需要 &lt;code&gt;curl&lt;/code&gt; 与 &lt;code&gt;python3&lt;/code&gt;）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# verify_login.sh — 登录接口回归验证&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://test.yunion.io&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cloudadmin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PASS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cloudadmin@test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;== TC-LOGIN-001 正确凭据登录 ==&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -o /tmp/login_ok.txt -w &lt;span class="s2"&gt;&amp;#34;%{http_code}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -c /tmp/login_cookie.txt &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -X POST -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s2"&gt;&amp;#34;{\&amp;#34;username\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;,\&amp;#34;password\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PASS&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;,\&amp;#34;domain\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/auth/login&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;HTTP &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PASS: 登录成功&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; grep -q yunionauth /tmp/login_cookie.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PASS: 已下发 yunionauth 凭证&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FAIL: 预期 200，实际 &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;== TC-LOGIN-002 错误密码登录 ==&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -w &lt;span class="s2"&gt;&amp;#34;\n%{http_code}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -X POST -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s2"&gt;&amp;#34;{\&amp;#34;username\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;,\&amp;#34;password\&amp;#34;:\&amp;#34;wrongpass123\&amp;#34;,\&amp;#34;domain\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/auth/login&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; head -n -1&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tail -n 1&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;HTTP &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -q IncorrectUsernameOrPassword &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PASS: 返回 IncorrectUsernameOrPassword&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FAIL: 未返回预期错误类型&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;== TC-LOGIN-003 不存在用户登录（提示应与错误密码一致） ==&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -w &lt;span class="s2"&gt;&amp;#34;\n%{http_code}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -X POST -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s2"&gt;&amp;#34;{\&amp;#34;username\&amp;#34;:\&amp;#34;no_such_user_9999\&amp;#34;,\&amp;#34;password\&amp;#34;:\&amp;#34;whatever\&amp;#34;,\&amp;#34;domain\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/auth/login&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; head -n -1&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tail -n 1&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;HTTP &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -q IncorrectUsernameOrPassword &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PASS: 与错误密码返回一致，未泄露账号是否存在&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FAIL: 错误类型与错误密码不一致&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;== TC-LOGIN-018 会话有效期 ==&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -D - -o /dev/null &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -X POST -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s2"&gt;&amp;#34;{\&amp;#34;username\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;,\&amp;#34;password\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PASS&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;,\&amp;#34;domain\&amp;#34;:\&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/auth/login&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -i &lt;span class="s1"&gt;&amp;#39;^set-cookie: yunionauth&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s1"&gt;&amp;#39;Max-Age=[0-9]*&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;yunionauth &lt;/span&gt;&lt;span class="nv"&gt;$exp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$exp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Max-Age=86399&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PASS: 有效期为 24 小时&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;WARN: 有效期与预期 86399 不同&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;登录成功后可用 &lt;code&gt;/tmp/login_cookie.txt&lt;/code&gt; 中的凭证调用其他业务接口，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s -b /tmp/login_cookie.txt &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/servers?limit=5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="附录-b本环境实测记录"&gt;附录 B：本环境实测记录&lt;/h2&gt;
&lt;p&gt;以下接口行为在 &lt;a href="https://test.yunion.io" target="_blank" rel="noopener noreferrer"&gt;https://test.yunion.io&lt;/a&gt; 实测确认（2026-09-15），可作为用例预期结果的基准。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;检查项&lt;/th&gt;
&lt;th&gt;实测结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;控制台可达性&lt;/td&gt;
&lt;td&gt;HTTP 200，HTTP/2，nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;登录接口&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /api/v1/auth/login&lt;/code&gt;，请求体 &lt;code&gt;{&amp;quot;username&amp;quot;,&amp;quot;password&amp;quot;,&amp;quot;domain&amp;quot;}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;正确凭据&lt;/td&gt;
&lt;td&gt;HTTP 200，响应体为空，下发 &lt;code&gt;yunionauth&lt;/code&gt;/&lt;code&gt;scope&lt;/code&gt;/&lt;code&gt;domain&lt;/code&gt;/&lt;code&gt;tenant&lt;/code&gt; Cookie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;错误密码&lt;/td&gt;
&lt;td&gt;HTTP 401，&lt;code&gt;{&amp;quot;class&amp;quot;:&amp;quot;IncorrectUsernameOrPassword&amp;quot;,&amp;quot;details&amp;quot;:&amp;quot;incorrect username or password&amp;quot;}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cloudadmin 默认 scope&lt;/td&gt;
&lt;td&gt;&lt;code&gt;system&lt;/code&gt;（管理后台视图）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cloudadmin 默认域&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cloudadmin MFA 状态&lt;/td&gt;
&lt;td&gt;未开启（凭证中 &lt;code&gt;totp_on=false&lt;/code&gt;、&lt;code&gt;totp_verified=false&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;登录凭证有效期&lt;/td&gt;
&lt;td&gt;86399 秒（24 小时）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;图形验证码接口&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /api/v1/auth/captcha&lt;/code&gt;，返回 &lt;code&gt;image/png&lt;/code&gt; 并下发 &lt;code&gt;captcha&lt;/code&gt; Cookie&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;：以上为接口层实测结论；依赖界面交互的用例（如验证码出现时机、MFA 交互、密码过期提示）仍需按用例步骤在浏览器中执行确认。&lt;/p&gt;</description></item></channel></rss>