如何在SpecFlow中从浏览器获取AuthToken复用登录状态?
一、核心思路
避免重复执行登录流程,仅在当前Feature的第一个Scenario中完成一次Azure登录,将认证信息(Cookie或Token)存入全局上下文,后续Scenario直接复用该信息跳过登录,解决频繁登录导致的系统过载问题。
二、具体实现方案
方法1:复用浏览器Cookie(推荐,兼容性更强)
登录成功后从WebDriver提取认证Cookie,存入FeatureContext全局上下文,后续Scenario直接加载该Cookie即可保持登录状态:
using OpenQA.Selenium; using OpenQA.Selenium.Support.UI; using System.Linq; using TechTalk.SpecFlow; [Binding] public class AuthHooks { private readonly IWebDriver _webDriver; private readonly FeatureContext _featureContext; public AuthHooks(IWebDriver webDriver, FeatureContext featureContext) { _webDriver = webDriver; _featureContext = featureContext; } // 初始化登录标记,仅在Feature启动时执行一次 [BeforeFeature(Order = 1)] public static void InitLoginFlag(FeatureContext featureContext) { featureContext["HasLoggedIn"] = false; } [BeforeScenario(Order = 1)] public void PrepareAuthState() { if (!(bool)_featureContext["HasLoggedIn"]) { // 执行完整登录流程 ExecuteAzureLogin(); // 提取并存储认证Cookie(根据实际站点调整Cookie名称) var authCookies = _webDriver.Manage().Cookies.AllCookies .Where(c => c.Name is ".AspNetCore.Cookies" or "ARRAffinity" or "AzureADAuthCookie") .ToList(); _featureContext["AuthCookies"] = authCookies; _featureContext["HasLoggedIn"] = true; } else { // 复用已存储的Cookie var storedCookies = (List<Cookie>)_featureContext["AuthCookies"]; foreach (var cookie in storedCookies) { _webDriver.Manage().Cookies.AddCookie(cookie); } // 跳转系统首页,无需再次登录 _webDriver.Navigate().GoToUrl("你的系统首页URL"); } } private void ExecuteAzureLogin() { _webDriver.Navigate().GoToUrl("你的Azure登录入口URL"); // 显式等待元素加载,替代隐式等待更可靠 var wait = new WebDriverWait(_webDriver, TimeSpan.FromSeconds(15)); // 输入账号 var accountInput = wait.Until(d => d.FindElement(By.Id("i0116"))); accountInput.SendKeys("测试账号"); wait.Until(d => d.FindElement(By.Id("idSIButton9"))).Click(); // 输入密码 var pwdInput = wait.Until(d => d.FindElement(By.Id("i0118"))); pwdInput.SendKeys("测试密码"); wait.Until(d => d.FindElement(By.Id("idSIButton9"))).Click(); // 处理保持登录提示(如果存在) wait.Until(d => d.FindElement(By.Id("idBtn_Back"))).Click(); // 等待跳转到系统首页,确认登录成功 wait.Until(d => d.Url.Contains("你的系统首页标识")); } }
方法2:提取并复用localStorage中的OIDC Token
如果系统通过OIDC将Token存储在浏览器localStorage中,可通过JavaScript提取Token,后续接口请求直接携带Token:
// 在登录成功后调用该方法提取Token private string GetOidcToken() { var jsExecutor = (IJavaScriptExecutor)_webDriver; // 替换为实际的localStorage键名,注意转义引号 var tokenKey = "oidc.user:https://login.microsoftonline.com/你的租户ID/v2.0:你的客户端ID"; var tokenJson = jsExecutor.ExecuteScript($"return localStorage.getItem('{tokenKey}');") as string; if (!string.IsNullOrEmpty(tokenJson)) { // 解析JSON提取access_token,需引用Newtonsoft.Json var tokenObj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(tokenJson); return tokenObj.access_token; } return null; }
提取到Token后,存入FeatureContext,后续Scenario中发起接口请求时,直接在请求头添加Authorization: Bearer {token}即可。
三、关键注意事项
- 上下文选择:使用
FeatureContext而非ScenarioContext,确保同一Feature下的所有Scenario复用同一登录状态;若需跨Feature复用,可通过ScenarioContext.ScenarioContainer注册单例服务存储认证信息。 - 有效期处理:Azure AD的Cookie和Token存在有效期,测试前确认有效期,避免中途失效导致测试失败。
- 显式等待:登录流程中必须使用
WebDriverWait显式等待元素加载,避免因页面加载延迟引发的元素定位失败。
内容的提问来源于stack exchange,提问作者oisin1min
相关产品推荐
相关产品推荐

