【问题标题】:Use Invoke-WebRequest with a username and password for basic authentication on the GitHub API在 GitHub API 上使用带有用户名和密码的 Invoke-WebRequest 进行基本身份验证
【发布时间】:2015-03-13 03:29:29
【问题描述】:

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

$ 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 - 好主意! :)

标签: powershell github-api basic-authentication


【解决方案1】:

这是使用 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 参数在答案中使用。
【解决方案2】:

这适用于我们的特定情况。

注释来自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 也在打破标准?

【讨论】:

    【解决方案3】:

    我知道这有点偏离 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 已经是一个加密字符串。

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

    【讨论】:

      【解决方案4】:

      如果有人需要一个班轮:

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

      【讨论】:

        【解决方案5】:

        另一种方法是使用 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
        

        【讨论】:

          【解决方案6】:

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

          $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
          

          【讨论】:

            【解决方案7】:

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

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

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

            基于 cmets 编辑:

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

            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 进行身份验证,您将需要手动构建标头
            【解决方案8】:

            Invoke-WebRequest 遵循@briantist 指出的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 是正确的,我需要将它操作为.e.g. foobar:barauth header key..
            • 当然,如果有人选择了非常安全的用户名和密码foo:bar,那么你需要使用不同的东西。
            【解决方案9】:

            使用这个:

            $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,没有添加任何标题。
            猜你喜欢
            • 1970-01-01
            • 2017-06-26
            • 2016-04-19
            • 1970-01-01
            • 2013-01-20
            • 1970-01-01
            • 2013-02-15
            • 2014-05-10
            • 2015-03-14
            相关资源
            最近更新 更多