ChatGPT解决这个技术问题 Extra ChatGPT

在 GitHub API 上使用带有用户名和密码的 Invoke-WebRequest 进行基本身份验证

使用 cURL,我们可以通过 HTTP Web 请求传递用户名,如下所示:

$ curl -u <your_username> https://api.github.com/user

-u 标志接受用户名进行身份验证,然后 cURL 将请求密码。 cURL 示例适用于 Basic authentication with the GitHub Api

我们如何将用户名和密码与 Invoke-WebRequest 一起传递?最终目标是在 GitHub API 中使用具有基本身份验证的 PowerShell 用户。

$pair 应该是 $pair = "$($user):$($pass)" 检查批准的答案。我正在使用上面的,它给了我太多的痛苦
建议使用 -Credential 方法的解决方案都不起作用,因为在发出请求时未生成正确的身份验证标头。
@Shaun Luttin - 这是一个问答网站,而不是问答网站。这个用户更愿意看到一个简洁的问题和答案,而不是适合您的特定情况,但不必阅读两次(一次在编辑的问题中,现在是 QuestionAnswer,然后再次在答案中)。如果问题是帮助您的答案不会最接近问题,StackExchange 具有使最佳/接受的答案尽可能接近问题的功能。
@user66001 感谢您的反馈。我已将我的问题答案移至其自己的答案以供以后参考。我认为这是一种改进。
@ShaunLuttin - 好主意! :)

b
briantist

我在这里假设基本身份验证。

$cred = Get-Credential
Invoke-WebRequest -Uri 'https://whatever' -Credential $cred

您可以通过其他方式(Import-Clixml 等)获取您的凭证,但它必须是 [PSCredential] 对象。

根据评论编辑:

正如他们在 link you provided 中解释的那样,GitHub 正在破坏 RFC:

API 支持 RFC2617 中定义的基本身份验证,但有一些细微差别。主要区别在于 RFC 要求使用 401 Unauthorized 响应来回答未经身份验证的请求。在许多地方,这会泄露用户数据的存在。相反,GitHub API 以 404 Not Found 响应。这可能会导致假定 401 Unauthorized 响应的 HTTP 库出现问题。解决方案是手动制作 Authorization 标头。

据我所知,Powershell 的 Invoke-WebRequest 在发送凭据之前会等待 401 响应,并且由于 GitHub 从未提供过响应,因此您的凭据将永远不会被发送。

手动构建标题

相反,您必须自己创建基本的身份验证标头。

基本身份验证采用由冒号 user:pass 分隔的用户名和密码组成的字符串,然后发送其 Base64 编码结果。

像这样的代码应该可以工作:

$user = 'user'
$pass = 'pass'

$pair = "$($user):$($pass)"

$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))

$basicAuthValue = "Basic $encodedCreds"

$Headers = @{
    Authorization = $basicAuthValue
}

Invoke-WebRequest -Uri 'https://whatever' -Headers $Headers

您可以组合一些字符串连接,但我想将其分解以使其更清晰。


正如我所说,它适用于基本身份验证,但我不知道 GitHub API 使用哪种身份验证。您可以发布一些有关预期内容的详细信息,这可能有助于我们解决问题。
啊,似乎 GitHub(他们自己承认)不遵循 RFC,但 Powershell 是。我已经用更多信息和解决方法编辑了答案。
是的,如果您要进行大量此类调用,我建议将其包装在一个函数中。正如我所说,为了清楚起见,我真的把所有的部分都分解了,但是你可以在一行上做所有的事情(这会很混乱)。
@Aref,您应该使用您正在使用的代码发布一个新问题。如果你这样做,让我知道我会看看。
如果也尝试针对 Visual Studio Team Services REST API 进行身份验证,则需要手动构建标头
m
mfralou

用这个:

$root = 'REST_SERVICE_URL'
$user = "user"
$pass= "password"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)

$result = Invoke-RestMethod $root -Credential $credential

出于某种原因,在 TFS vNext 上使用它时,选择的答案对我不起作用,但这一个成功了。非常感谢!
所选答案不适用于在 azure 上运行 powershell runbook 以启动触发作业,但此答案确实有效。
对我不起作用。根据 Fiddler,没有添加任何标题。
K
Karol Berezicki

如果有人需要一个班轮:

iwr -Uri 'https://api.github.com/user' -Headers @{ Authorization = "Basic "+ [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("user:pass")) }

L
Leonard Brünings

正如@briantist 所指出的,Invoke-WebRequest 遵循 RFC2617,但是如果 Authorization 标头不存在,某些系统(例如 JFrog Artifactory)允许匿名使用,但如果标头包含无效凭据,则会以 401 Forbidden 响应。

这可用于触发 401 Forbidden 响应并使 -Credentials 工作。

$login = Get-Credential -Message "Enter Credentials for Artifactory"

                              #Basic foo:bar
$headers = @{ Authorization = "Basic Zm9vOmJhcg==" }  

Invoke-WebRequest -Credential $login -Headers $headers -Uri "..."

这将在第一次发送无效标头,由于 -Credentials 覆盖 Authorization 标头,因此将在第二次请求中将其替换为有效凭据。

使用 Powershell 5.1 测试


如果您在给出用户和密码的情况下使用 credential,则是否需要基本授权标头?根据您的回答,-credential 仅在它之前从 headers 获得 401 时才有效,因此必须有 basic foo:bar 以便它不是匿名的?
是的,正如我在回答中所写,如果允许混合访问,您需要将无效凭据添加到 Authorization 标头触发 401 以使 -Credential 工作。
因此,如果 foo:bar 是正确的,我需要将其操作为 .eg foobar:bar 用于 auth header key ..
当然,如果有人选择了非常安全的用户名和密码 foo:bar,那么您需要使用不同的东西。
l
livy111

我必须这样做才能让它工作:

$pair = "$($user):$($pass)"
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Pair))
$headers = @{ Authorization = "Basic $encodedCredentials" }
Invoke-WebRequest -Uri $url -Method Get -Headers $headers -OutFile Config.html

R
Rafael Pazos

这是使用WebRequest的另一种方式,我希望它对你有用

$user = 'whatever'
$pass = 'whatever'
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
$headers = @{ Authorization = "Basic Zm9vOmJhcg==" }  
Invoke-WebRequest -Credential $credential -Headers $headers -Uri "https://dc01.test.local/"

以防万一有人想知道,-Headers 参数需要 [string],[string] 的字典或哈希表。您实际上可以只定义一个数组 - 例如 @(Authorization = 'Basic ...') 就像他在这里所做的那样,powershell 会为您转换它
@KellenStuart 不要将 basicdigest 混合,后者在答案中与 credential 参数一起使用。
S
Shaun Luttin

这对我们的特殊情况有效。

注释来自 Wikipedia on Basic Auth from the Client Side。感谢@briantist's answer的帮助!

将用户名和密码组合成一个字符串 username:password

$user = "shaunluttin"
$pass = "super-strong-alpha-numeric-symbolic-long-password"
$pair = "${user}:${pass}"

将字符串编码为 Base64 的 RFC2045-MIME 变体,但不限于 76 个字符/行。

$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)

创建 Auth 值作为方法、一个空格,然后是编码对 Method Base64String

$basicAuthValue = "Basic $base64"

创建标头 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

$headers = @{ Authorization = $basicAuthValue }

调用网络请求

Invoke-WebRequest -uri "https://api.github.com/user" -Headers $headers

PowerShell 版本比 cURL 版本更详细。这是为什么? @briantist 指出 GitHub 正在破坏 RFC,而 PowerShell 则坚持使用它。这是否意味着 cURL 也违反了标准?


m
mayursharma

另一种方法是使用 certutil.exe 将您的用户名和密码保存在一个文件中,例如 in.txt 作为用户名:密码

certutil -encode in.txt out.txt

现在您应该可以使用 out.txt 中的 auth 值了

$headers = @{ Authorization = "Basic $((get-content out.txt)[1])" }
Invoke-WebRequest -Uri 'https://whatever' -Headers $Headers

E
Ernest Correale

我知道这与 OP 的原始请求有点不同,但我在寻找一种方法来针对需要基本身份验证的站点使用 Invoke-WebRequest 时遇到了这个问题。

不同的是,我不想在脚本中记录密码。相反,我想提示脚本运行程序输入该站点的凭据。

这是我的处理方式

$creds = Get-Credential

$basicCreds = [pscredential]::new($Creds.UserName,$Creds.Password)

Invoke-WebRequest -Uri $URL -Credential $basicCreds

结果是脚本运行器被提示带有 U/P 的登录对话框,然后 Invoke-WebRequest 能够使用这些凭据访问该站点。这是因为 $Creds.Password 已经是一个加密字符串。

我希望这可以帮助寻找上述问题的类似解决方案但没有在脚本中保存用户名或密码的人