PowerShell访问启用SSO/SAML与2FA的网页遇授权问题求助
问题原因分析
你当前的脚本存在核心问题:获取的是Microsoft Graph API的访问令牌,而你的目标网站采用的是SAML-based SSO认证,这两种认证机制不兼容。Graph令牌的受众是https://graph.microsoft.com,目标网站不会识别或接受该令牌,因此返回登录页面是预期结果。
解决方案
要访问SAML认证的网站并获取会话权限,你需要模拟浏览器的完整SAML登录流程,最终获取网站的会话Cookie,而非使用Graph令牌。以下是具体实现思路和示例:
1. 核心思路:模拟SAML登录会话
SAML认证的本质是通过身份提供商(Azure AD)生成断言,提交给目标网站以建立信任会话。你需要:
- 访问目标网站,触发SAML跳转至Azure AD登录页
- 完成2FA认证(交互式或自动化方式)
- 获取目标网站的会话Cookie,用于后续请求
2. PowerShell实现方案(模拟浏览器会话)
方案A:手动交互式获取会话Cookie
通过PowerShell的WebSession保持会话,手动完成2FA认证后复用Cookie:
# 初始化会话对象,用于保持Cookie $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession # 第一步:访问目标网站,触发SAML跳转 $initialResponse = Invoke-WebRequest -Uri "https://our.website" -WebSession $session -MaximumRedirection 0 -ErrorAction SilentlyContinue # 第二步:解析跳转的Azure AD登录URL(根据实际响应调整解析逻辑) $loginUrl = ($initialResponse.Headers.Location | Select-Object -First 1) # 第三步:打开浏览器手动完成2FA登录,然后导出会话Cookie # 这里可以用Selenium模块模拟浏览器操作,或者手动登录后从浏览器导出Cookie # 示例:使用Selenium模拟浏览器登录(需先安装Selenium模块) Install-Module -Name Selenium -Scope CurrentUser -Force $driver = Start-SeChrome $driver.Navigate().GoToUrl($loginUrl) # 等待你手动完成2FA登录,登录后回到目标网站 Read-Host "请在浏览器中完成登录,按回车继续..." # 导出浏览器中的会话Cookie到PowerShell的WebSession $cookies = $driver.Manage().Cookies.AllCookies foreach ($cookie in $cookies) { $sessionCookie = New-Object System.Net.Cookie( $cookie.Name, $cookie.Value, $cookie.Path, $cookie.Domain ) $session.Cookies.Add($sessionCookie) } $driver.Quit() # 第四步:使用会话Cookie访问目标网站,下载JNLP文件 $jnlpResponse = Invoke-WebRequest -Uri "https://our.website/path/to/agent.jnlp" -WebSession $session $jnlpResponse.Content | Out-File -Path "agent.jnlp" -Encoding UTF8
方案B:自动化设备码认证(适合无交互场景)
如果目标网站支持Azure AD的OAuth2设备码流程,可以无需手动打开浏览器完成2FA:
$tenantId = "你的Azure AD租户ID" $clientId = "注册的Azure AD应用客户端ID" # 需要提前在Azure AD注册应用并授予目标网站的权限 # 获取设备码 $deviceCodeParams = @{ Uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/devicecode" Method = "Post" Body = @{ client_id = $clientId scope = "https://our.website/.default" # 替换为目标网站的资源ID } } $deviceCode = Invoke-RestMethod @deviceCodeParams Write-Host "请在设备上打开 $($deviceCode.verification_uri),输入代码 $($deviceCode.user_code) 完成认证" # 轮询获取访问令牌 $tokenParams = @{ Uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" Method = "Post" Body = @{ grant_type = "urn:ietf:params:oauth:grant-type:device_code" client_id = $clientId device_code = $deviceCode.device_code } } do { Start-Sleep -Seconds $deviceCode.interval try { $tokenResponse = Invoke-RestMethod @tokenParams break } catch { $status = $_.Exception.Response.StatusCode.value__ if ($status -ne 408 -and $status -ne 400) { throw } } } while ($true) # 使用访问令牌请求目标网站(仅当目标网站支持OAuth2 Bearer认证时有效,SAML网站可能仍需会话Cookie) $headers = @{ Authorization = "Bearer $($tokenResponse.access_token)" } $response = Invoke-WebRequest -Uri "https://our.website" -Headers $headers -WebSession $session # 若返回登录页面,仍需用方案A的会话Cookie方式
3. 关键注意事项
- 令牌受众匹配:确保获取的令牌受众是目标网站的资源ID,而非Graph API
- 会话Cookie复用:SAML认证依赖会话Cookie,而非Bearer令牌,这是访问SAML网站的核心
- Jenkins Agent替代方案:如果Jenkins本身支持Azure AD SSO,可以直接使用Jenkins的官方认证方式启动Agent,无需手动处理SSO流程
内容的提问来源于stack exchange,提问作者Richard Gledhill
相关产品推荐
相关产品推荐

