Ghost CMS API 来自 R

huangapple go评论83阅读模式
英文:

Ghost CMS API from R

问题

我正在尝试使用内置的 Admin API 从 R 连接到本地的 Ghost CMS 实例。有一份很好的文档 (https://ghost.org/docs/admin-api/#token-authentication),介绍了如何在各种编程语言中进行连接,但不幸的是没有提供 R 的说明。我已经编写了以下代码,但在尝试创建测试文章时不幸收到了 401 错误。非常感谢任何帮助。

R 代码:

api_admin_key <-
  "xxxxxx:yyyyyyyyyyyyyyy"

api_admin_key <- unlist(strsplit(x = api_admin_key, split = ":"))
names(api_admin_key) <- c("id", "secret")

# 准备头部和负载
iat <- as.integer(Sys.time())
header <-
  list(alg = 'HS256', typ = 'JWT', kid = api_admin_key[["id"]])

# 创建令牌(包括解码密钥)
payload <-
  jose::jwt_claim(iat = iat,
                  exp = iat + 5 * 60,
                  aud = '/admin/')

token <-
  jose::jwt_encode_hmac(
    claim = payload,
    secret = charToRaw(api_admin_key[["secret"]]),
    size = 256,
    header = header
  )

# 发送经过身份验证的请求以创建文章
url <- 'http://localhost:2368/ghost/api/admin/posts/'
headers <- c('Authorization' = paste("Ghost", token))
body <- list(posts = list(
    "title" = 'Hello World',
    "html" = "<p>My post content. Work in progress...</p>",
    "status" = "published"
  )
)

httr::POST(url,
           body = body,
           encode = "json",
           httr::add_headers(.headers = headers))

<details>
<summary>英文:</summary>

I am trying to connect to a local Ghost CMS instance from __R__ using the build-in Admin API. There is a good documentation ([https://ghost.org/docs/admin-api/#token-authentication][1]) on how to connect for various languages but unfortunately not for __R__. I have compiled the following code but unfortunately receive a 401 error when trying to create a test post. Any help is much appreciated.

__R__ code:

    api_admin_key &lt;-
      &quot;xxxxxx:yyyyyyyyyyyyyyy&quot;
    
    api_admin_key &lt;- unlist(strsplit(x = api_admin_key, split = &quot;:&quot;))
    names(api_admin_key) &lt;- c(&quot;id&quot;, &quot;secret&quot;)
    
    # Prepare header and payload
    iat &lt;- as.integer(Sys.time())
    header &lt;-
      list(alg = &#39;HS256&#39;, typ = &#39;JWT&#39;, kid = api_admin_key[[&quot;id&quot;]])
    
    # Create the token (including decoding secret)
    payload &lt;-
      jose::jwt_claim(iat = iat,
                      exp = iat + 5 * 60,
                      aud = &#39;/admin/&#39;)
    
    token &lt;-
      jose::jwt_encode_hmac(
        claim = payload,
        secret = charToRaw(api_admin_key[[&quot;secret&quot;]]),
        size = 256,
        header = header
      )
    
    # Make an authenticated request to create a post
    url &lt;- &#39;http://localhost:2368/ghost/api/admin/posts/&#39;
    headers &lt;- c(&#39;Authorization&#39; = paste(&quot;Ghost&quot;, token))
    body &lt;- list(posts = list(
        &quot;title&quot; = &#39;Hello World&#39;,
        &quot;html&quot; = &quot;&lt;p&gt;My post content. Work in progress...&lt;/p&gt;&quot;,
        &quot;status&quot; = &quot;published&quot;
      )
    )
    
    httr::POST(url,
               body = body,
               encode = &quot;json&quot;,
               httr::add_headers(.headers = headers))


  [1]: https://ghost.org/docs/admin-api/#token-authentication

</details>


# 答案1
**得分**: 2

看起来问题出在你传递给 `jwt_encode_hmac()` 的 `secret=` 参数上。`charToRaw` 函数不能理解十六进制数字。它只使用ASCII字符代码。要进行转换,你需要使用来自[这个现有问题](https://stackoverflow.com/questions/70884796/convert-hexadecimal-string-to-bytes-in-r)的其中一个 `hex_to_raw` 函数。我将在这里使用一个:

```R
hex_to_raw <- function(x) {
  digits <- strtoi(strsplit(x, "")[[1]], base=16L)
  as.raw(bitwShiftL(digits[c(TRUE, FALSE)],4) + digits[c(FALSE, TRUE)])
}

此外,你不需要在头部指定 alg 和 typ,因为这些信息将由函数自动添加。所以你可以使用以下方式构建你的令牌:

api_admin_key <- "adam:12bd18f2cd12"

api_admin_key <- unlist(strsplit(x = api_admin_key, split = ":"))
names(api_admin_key) <- c("id", "secret")

# 准备头部和负载
iat <- as.integer(Sys.time())
header <- list(kid = api_admin_key[["id"]])

# 创建令牌(包括解码密钥)
payload <-
  jose::jwt_claim(iat = iat,
                  exp = iat + 5 * 60,
                  aud = '/admin/')

token <-
  jose::jwt_encode_hmac(
    claim = payload,
    secret = hex_to_raw(api_admin_key[["secret"]]),
    size = 256,
    header = header
  )

我使用了 https://jwt.io/ 上的调试器测试了每个令牌,它们似乎是等效的。在调试器中,十六进制值 "12bd18f2cd12" 的 base64 编码值是 "Er0Y8s0S"。

英文:

It looks like the problem is the secret= you are passing to jwt_encode_hmac(). The charToRaw doesn't understand hex digits. It's just using the ascii character codes. To do the translation, you'd need one of the hex_to_raw functions from this existing question. I'll use one here

hex_to_raw &lt;- function(x) {
  digits &lt;- strtoi(strsplit(x, &quot;&quot;)[[1]], base=16L)
  as.raw(bitwShiftL(digits[c(TRUE, FALSE)],4) + digits[c(FALSE, TRUE)])
}

Also, you don't need to specify the alg and typ in the header because those are added by the function, So you would build your token with

api_admin_key &lt;- &quot;adam:12bd18f2cd12&quot;

api_admin_key &lt;- unlist(strsplit(x = api_admin_key, split = &quot;:&quot;))
names(api_admin_key) &lt;- c(&quot;id&quot;, &quot;secret&quot;)

# Prepare header and payload
iat &lt;- as.integer(Sys.time())
header &lt;- list(kid = api_admin_key[[&quot;id&quot;]])

# Create the token (including decoding secret)
payload &lt;-
  jose::jwt_claim(iat = iat,
                  exp = iat + 5 * 60,
                  aud = &#39;/admin/&#39;)

token &lt;-
  jose::jwt_encode_hmac(
    claim = payload,
    secret = hex_to_raw(api_admin_key[[&quot;secret&quot;]]),
    size = 256,
    header = header
  )

I tested each of the tokens using the debugger at https://jwt.io/ and they seemed equivalant. Using the debugger, the base64 encoded value for the hexvalue "12bd18f2cd12" is "Er0Y8s0S"

huangapple
  • 本文由 发表于 2023年8月4日 03:56:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76831268.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定