PowerShell的Invoke-RestMethod等同于curl -u(基本身份验证)

96

等同于什么?

curl -u username:password ...

在PowerShell的Invoke-RestMethod中应该怎么做?我尝试了这个:

$securePwd = ConvertTo-SecureString "password" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($username, $securePwd)

Invoke-RestMethod -Credential $credential ...

但是它返回401,未经授权。


1
阅读下面的评论,其中包含一些适用于某些场景但有限制条件的多行解决方案,让我感到悲哀的是,微软的伟大脚本语言竟然没有一个简单的等效替代品来执行“curl -u用户名:密码”的操作。唉,我的解决方案是下载curl.exe。 - pettys
@pettys 是的,没错,很多咨询...... 顺便说一下,curl 已经被包含在 Windows 中很长一段时间了(不是 posh 别名)。 - Jaqueline Vanek
好的,我明白了!我现在看到,在Win 10版本17063中,curl.exe被添加到了C:\Windows\System32目录下。@JaquelineVanek,我不确定你所有评论的意义,但我很高兴现在它已经在那里了。 - pettys
1
你尝试过在 Invoke-RestMethod 的参数中添加 -Authentication Basic 吗?其他部分保持不变,这对我来说完全可行。背景:我正在从环境变量中获取凭据并查询Zendesk HelpCenter API。 - pavol.kutaj
9个回答

144

这是目前为止对我有效的唯一方法:

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

Invoke-RestMethod -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} ...

但我不相信没有更好的方法。


在简化 GetBytes 参数为 '("username:password")' 后,它对我们起作用了。谢谢! - Pieterjan Spoelders

24

我不确定为什么在你的情况下-Credential参数无法工作,但它可以与httpbin服务一起使用。

你可以尝试这个:

$pwd = ConvertTo-SecureString "MyPassword" -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ('PsUser', $pwd)

Invoke-RestMethod 'http://httpbin.org/basic-auth/PsUser/MyPassword' -cred $cred

编辑: 如评论中所述,该方法在初始请求时不会发送授权头信息。 它会等待挑战响应,然后重新发送带有授权头信息的请求。 这对于需要在初始请求上提供凭据的服务将无法使用。


1
那跟问题中的代码片段有什么不同? - Borek Bernard
我确认它确实适用于基本身份验证,并提供了一个URL来测试它。我不希望用户来到这个问题寻找如何使用基本身份验证,然后被告知“-Credential”无法工作。在我提供的示例中,它显然是有效的。一定是你的情况中有些东西导致了它的破坏。 - Rynant
啊,对不起,我错过了您建议针对特定URL进行测试的建议。在我的情况下,curl可以工作,我提供授权HTTP头的“手动”方法也可以工作,只是凭据参数不行。您不知道它内部做什么吗?它只是添加相同的HTTP标头吗? - Borek Bernard
2
经过在运行 WireShark 时对比 httpbin.org,我发现使用“-Credential”选项不会在第一个请求中添加授权标头。Httpbin.org 返回 401,然后 PowerShell 发送第二个请求,该请求具有授权标头。第二个请求后,Httpbin.org 返回 200。据我所知,你的方法是在第一个请求中发送标头的唯一方法。 - Rynant
我刚在http://weblog.west-wind.com/posts/2010/Feb/18/NET-WebRequestPreAuthenticate-not-quite-what-it-sounds-like发现了这篇博客文章,它讨论了与HttpWebRequest相同的问题,而PowerShell可能使用它来发送HTTP请求。 - Rynant

19
#Requires -Version 6
$Uri = 'https://httpbin.org/basic-auth/user/pass'
# use "user" and "pass" when prompted for credentials
$Credential = Get-Credential
Invoke-RestMethod -Uri $Uri -Authentication Basic -Credential $Credential

2
这里有很多非常古老的回答,但这是正确的现代答案。提供一个凭据对象并在PowerShell中指定“-Authentication Basic”以实现简单的基本身份验证。 - FoxDeploy
但在Windows Powershell中似乎不起作用? - NickG
@NickG 显然,正如所述 #Requires -Version 6 - Jaqueline Vanek
1
@BorisVerkhovskiy 获取帮助 Get-Credential -Examples``` 或者只需访问 https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.security/get-credential?view=powershell-7.3 ex4 - Jaqueline Vanek
1
@BorisVerkhovskiy 替代符号 $cred = [pscredential]::new($StringUserName, $SecureStringPassword) 你可能想要看一下 'SecureString' 这个东西是如何工作的 - Jaqueline Vanek
显示剩余2条评论

14

当它们单独失败时,似乎您应该结合方法。

创建凭据并将其添加到请求中。

创建头并将其添加到请求中。

$username = "username";
$password = ConvertTo-SecureString –String "password" –AsPlainText -Force
$credential = New-Object –TypeName "System.Management.Automation.PSCredential" –ArgumentList $username, $password

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

$getProjectUri = "yourUri"
Invoke-RestMethod -Method Get -Uri $getProjectUri -Headers @{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"

这里似乎缺少一个引用,应该加上吗? - Paul Deen
1
不确定如何处理这个问题,我说“应该”是因为在某些情况下,一些实现似乎需要在第一次请求时同时使用凭据,就像Borek和@Rynant发现的那样。因此,有时候,根据所调用的服务器,您可能需要结合使用这两种方法。 - Montané Hamilton
1
确认已经成功将从VSO下载的构件合并。谢谢。 - Carl Krig

6

这个版本适用于Get-CredentialPSCredential对象。它还可以在PowerShell 6.0中跨平台使用。它通过避免使用BSTR调用来实现这一点,有时在尝试从PSCredential中提取密码时会建议使用。

$creds = Get-Credential
$unsecureCreds = $creds.GetNetworkCredential()
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $unsecureCreds.UserName,$unsecureCreds.Password)))
Remove-Variable unsecureCreds

Invoke-RestMethod -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} ...

5

我发现使用-WebSession参数是有效的,只要你提前创建一个带有凭据的WebRequestSession对象。我不会再重复如何创建PS Credential对象,因为其他答案已经讲过了。

$WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession -Property @{Credentials=$Credential}
Invoke-RestMethod -Uri "your_URI" -WebSession $WebSession

这种方法在第一次调用时发送auth头,因此避免了401响应。

顺便提一下,这种方法也可以用于设置代理详细信息(如果使用参数指定,则不适用于所有版本的PS),并处理cookie,如果您的API需要。


5

您基本上需要将用户名和密码作为编码凭据变量传递给Invoke-RestMethod

对我有效的方法如下:

$USERNAME = 'user'
$PASSWORD = 'password'
$IDP_URL = 'example.com/token'


$credPair = "$($USERNAME):$($PASSWORD)"
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair))

$parameters = @{
    Uri         = $IDP_URL
    Headers     = @{ 'Authorization' = "Basic $encodedCredentials" }
    Method      = 'POST'
    Body        = '...'
    ContentType = '...'
}

Invoke-RestMethod @parameters

请注意,您可以将请求参数提取为$parameters,以避免使您的命令膨胀。

2
我知道这是一个非常老的问题,但我想在这里分享一些更新。对于使用PowerShell进行基本身份验证的所有帖子都无法正常工作。经过多次尝试和阅读MS文档后,我发现我需要使用-AllowUnencryptedAuthentication参数,因为我是使用http连接。我还不得不升级我的PS版本以获得访问该参数的权限。
从参数的描述中可以看出:"允许在未加密的连接上发送凭据和秘密。默认情况下,当使用Uri而不是https://开始的任何身份验证选项或凭据时,将导致错误并且请求将中止,以防止意外地在未加密的连接上以明文形式通信秘密。要自行承担风险覆盖此行为,请提供AllowUnencryptedAuthentication参数。"

0
我花了几天时间尝试上述所有示例,但都没有成功。最终我发现我需要指定POST方法。例如:
$request =  Invoke-WebRequest -Method Post -Uri "https://www.emea-api.morningstar.com/token/oauth" -Headers @{accept='*/*';Authorization='Basic bWFy...encoded username:password...='};

-mobailey


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接