辛宝Otto

辛宝Otto 的玄酒清谈

北漂前端程序员儿 / 探索新事物 / Web Worker 主播之一/内向话痨
xiaoyuzhou
email

技術折騰 xLog 2 深入理解 xlog 的鑑權

技術折騰 xLog 2 深入理解 xlog 的鑑權

內部鏈接

  • [[技術折騰 xLog 1 可行性探索]]
  • [[技術折騰 xLog 2 深入理解 xlog 的鑑權]]
  • [[技術折騰 xLog 3 實現一個 obsidian 插件]]
  • [[技術折騰 xLog 4 用 unStorage 封裝 xLogDriver]]
  • [[速通 - xLog 背後的 CrossBell SDK]]
  • [[從官方 XLOG Obsidian 插件中能學到什麼]]
  • [[開發 Obsidian Sync To Xlog 插件之 處理 obsidian 的圖片]]
  • [[速通 - CrossBell 的開源作品]]
  • [[速通 Obsidian Docs - 側重插件開發]]

本文繼續探索,承接 [[技術折騰 xLog 1 可行性探索]] 文章的內容。

本文嘗試實現 xlog 文章的管理,實現自己內容的增刪改查,基於官方的 openapi。本文價值 5 個幣的讚賞,嘻嘻

背景#

如果要實現 xlog 文章的管理操作,這就需要鑑權,如何證明你是你,你能修改某個人的文章?在 web2 領域,我們一般會通過帳號密碼生成 jwt 模擬用戶,或者通過 oauth 獲得 access-token 授權操作特定的權限範圍。

我們的技術前提是任意運行時環境,同時支持瀏覽器和 node.js 等不同運行環境,所以不考慮了網頁端小狐狸 metamask 方式授權。

技術實現#

經過一番探索,和官方成員的 diygod 的指導,目前至少有兩種方式實現數據授權管理,私鑰和授權碼,推薦第二種。

透過 Private Key#

首先是透過 private key,錢包的私鑰。這種是萬能的我證明是我的的方案,官方 sdk 也支持透過 private key 實現鑑權。

比如這裡 https://crossbell.js.org/#md:connect-with-private-key

private key 從哪裡來呢?舉例小狐狸:

image.png

在帳戶詳情裡,有個 Show Private Key。配合官方 SDK 可以實現鑑權。

請務必注意:private key 非常機密,使用它也非常危險,這裡只做技術介紹。

對於用戶和開發者,更推薦下面的方案,授權 token 方案。

透過 siwe 授權#

SIWE 是 sign in with ethereum 的縮寫。

透過 siwe 授權有以下幾個步驟:

  • 開啟 siwe 功能
  • 獲取 token
  • 透過 api 獲得授權

開啟 siwe 功能#

首先訪問自己的 xlog 控制台 https://xlog.app/dashboard/ 在左側菜單欄最後一列選擇設置。

選擇 xSettings ,會有下圖的展示:

image.png

我對 web3 不是很熟悉,口語化表達,圓框內的解釋可以這樣理解,主要是 Sync Operator 部分:

  • 操作授權。
  • 同步操作。透過開啟 Sync Operator 可以允許透過其他方式同步內容到 Crossbell 也就是 xlog

一旦開啟,我們就擁有了透過代碼同步內容到 xlog 的能力。

獲取 token#

目前獲取 token 的最簡單方案是在控制台中這樣操作:

在 xsetting 頁面,單擊右鍵選擇檢查,或者開啟開發者模式,或者按 F12,推薦使用 Chrome。會彈出一個模塊,選擇 控制台 Console,複製下面代碼到控制台,按回車,會返回一長串文字。

JSON.parse(localStorage.getItem('connect-kit:account')).state.wallet.siwe.token

這段代碼的作用是獲取 siwe 的 token 信息,應該還有其他方案獲取,目前這種方案最簡單。

輸入這段代碼返回的內容就是需要的 token 信息,請自行保存好。

請注意不要兩端的單引號,只要內容。(算了,我做個防呆設計,做個程序兼容吧。)

請複製控制台返回這一長串內容,這個叫鑑權 token,插件裡會用到。

對開發者來說,在 node.js 項目中透過 .env 存儲,在 github 中透過 secret 存儲。避免明文暴露。

api 實踐#

補充:也推薦使用 crossbell 的 sdk,效果是一致的。

有了剛才獲得的 token,我們訪問 https://indexer.crossbell.io/docs#/Siwe 官方提供的文檔,我們所需要的所有東西都在這裡了。

image.png

翻到頁面最頂部,有個綠色的 Authorize 按鈕,點擊彈出一個彈窗,把剛才的 token 填寫到 siwe 內容裡

image.png

點擊授權,這時候我們在每次請求的 header 裡會添加 Authorization: Bearer ${token}

比如我們使用 GET /v1/siwe/account 就可以獲取當前我們是誰了。

image.png

剩下的事情就簡單了,有這樣幾個接口可以自行實踐:

  • PUT /v1/siwe/contract/characters/{characterId}/notes 給用戶新建文章
  • POST /v1/siwe/contract/characters/{characterId}/notes/{noteId}/metadata 更新指定 noteId 的文章
  • Delete /v1/siwe/contract/characters/{characterId}/notes/{noteId} 刪除指定的文章

提供幾個代碼片段,經過幾次嘗試,一下代碼片段有效。

首先是創建文章:

const title = '文章標題'
const content = '文章內容'
const base = "https://indexer.crossbell.io";
const ottoCharId = ''
const token = ''

const createPost = async () => {
  const url = `/v1/siwe/contract/characters/${ottoCharId}/notes`;

  const finalUrl = base + url;

  axios
    .request({
      method: "put",
      url: finalUrl,
      headers: {
        Authorization: `Bearer ${token}`,
      },
      data: {
        metadata: {
          tags: ["post"],
          type: "note",
          title: title,
          content: content,
          summary: "",
        sources: ["xlog"],
          attributes: [
            {
              value: "play-xlog-01", // 這裡是自定義 slug
              trait_type: "xlog_slug",
            },
          ],
          attachments: [
            {
              name: "cover", // cover
              address: "",
              mime_type: "",
            },
          ],
        },
        locked: false,
        linkItemType: null,
      },
    })
    .then((res) => {
      console.log(2, res.data);
    })
    .catch((err) => {
      console.log(3, err);
    });
};

然後是更新文章,注意這裡的 mode 從字面意思看 replace 比較簡單

const updatePost = async () => {
  const noteId = 29;
  const mode = "replace"; //'merge'

  const updatePost =
    base +
    `/v1/siwe/contract/characters/${ottoCharId}/notes/${noteId}/metadata`;

  axios
    .request({
      method: "post",
      url: updatePost,
      headers: {
        Authorization: `Bearer ${token}`,
      },
      data: {
        metadata: {
          tags: ["post", "新想法"],
          type: "note",
          title: title,
          content: content,
          sources: ["xlog"],
          // summary: "",
          attributes: [
            {
              value: "play-xlog-01",
              trait_type: "xlog_slug",
            },
          ],
          attachments: [
            {
              name: "cover",
              address: "",
              mime_type: "",
            },
          ],
        },
        mode,
      },
    })
    .then((res) => {
      console.log(JSON.stringify(res.data, null, 2));
    })
    .catch((err) => {
      console.log(3, err);
    });
};

最後是刪除文章

const deletePost = async () => {
  const characterId = '';
  const noteId = '';

  const deletePost =
    base + `/v1/siwe/contract/characters/${characterId}/notes/${noteId}`;

  axios
    .request({
      method: "delete",
      url: deletePost,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
    .then((res) => {
      console.log(2, res.data);
    })
    .catch((err) => {
      console.log(3, err);
    });
};

踩坑經驗#

創建文章的 body,和獲取列表頁的返回體不一樣,主要是 content 是否多包一層,也就是請求參數和入庫的數據不一樣,稍微有點坑,最終創建文章的參數可用。

官方對入參比較寬容,啥參數都要,笑死,錯誤參數會導致列表頁展示不出來,排查好久眼都花了,還是萬分小心,仔細核對,等熟悉了官方源碼,得加一加限制。

展望#

有了上述的 api 實踐內容,我們未來可以做到以下事情:

  • 編寫 node 腳本,實現文章的創建和更新
  • 比如在 github actions 裡,每次推送了 markdown 可以調用函數,同步到 xlog
  • 比如在 obsidian 裡編寫插件,單擊右鍵上傳到 xlog
  • 接入自己的 cms 後台,進行文章管理

接下來,我會改造我的 obsidian 插件,實現上傳文件到 xlog

image.png

敬請期待。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。