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

通过 cURL,我们可以传递一个带有 HTTP web 请求的用户名,如下所示:

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

-u标志接受用户名进行身份验证,然后 cURL 将请求密码。CURL 示例适用于 使用 GitHub Api 进行基本身份验证

我们如何以类似的方式传递用户名和密码以及 Invoke-WebRequest?最终目标是在 GitHub API 中使用具有 Basic 身份验证的 PowerShell。

320798 次浏览

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

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

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

根据评论进行编辑:

GitHub 正在破坏 RFC,正如他们在 你提供的链接中解释的那样:

API 支持 RFC2617中定义的基本身份验证(Basic Authentication) 主要的区别是 RFC 需要 未经身份验证的请求将以401未经授权应答 在许多地方,这会暴露用户的存在 取而代之的是,GitHub API 的响应是404 Not Found 对于假定401未经授权的 HTTP 库来说,会导致问题 解决方案是手工制作授权标头。

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

手动构建标题

相反,您必须自己创建基本的 auth 头文件。

基本身份验证采用一个字符串,该字符串由用户名和密码组成,用冒号 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

你可以把一些字符串串联起来,但是我想把它们分开,使它们更清晰。

用这个:

$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

正如@briantist 指出的那样,Invoke-WebRequest遵循 RFC2617,但是有一些系统(例如 JFrog ArtiFactory)允许在没有 Authorization报头的情况下匿名使用,但是如果报头包含无效凭据,则会响应 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进行测试

我必须这么做才能成功:

$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

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

certutil -encode in.txt out.txt

现在您应该能够使用 out.txt 中的 auth 值了

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

如果有人需要一句话:

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

我知道这有点偏离运营商最初的要求,但我是在寻找一种方法来使用 Invoke-WebRequest 对付一个需要基本认证的网站时发现这一点的。

区别在于,我不想在脚本中记录密码。相反,我想提示脚本运行程序获取站点的凭据。

我是这么处理的

$creds = Get-Credential


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


Invoke-WebRequest -Uri $URL -Credential $basicCreds

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

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

这就是我们的特殊情况。

注释来自 基于客户端的基本认证维基百科。感谢 @ Briantist 的回答的帮助!

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

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

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

$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 也与标准不符?

下面是另一种使用 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/"