智能合约中的OAuth和API认证

OAuth是主流的API认证和授权方式,用户无须暴露其身份信息即可访问各种网站和应用。有了Chainlink外部适配器 ,就可以在链下展开复杂的运算。

# 智能合约中的OAuth和API认证 ![](https://img.learnblockchain.cn/2020/11/12_/526505414.png) [OAuth](https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth#https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth)是主流的[API认证和授权](https://swagger.io/docs/specification/authentication/)方式,用户无须暴露其身份信息即可访问各种网站和应用。乍一看,我们似乎很难从OAuth这样的链下Web2服务中获取数据并上传至链上智能合约。然而,有了[Chainlink外部适配器 ](https://docs.chain.link/docs/external-adapters),就可以在链下展开复杂的运算,这与基于OAuth的API认证无任何差异。接入外部适配器后,就可以使用OAuth访问更多安全的链下数据源,并轻松实现与链上智能合约的交互。我们可以从Solidity或其他智能合约中调用这些安全的API,访问各种服务并同时保障安全。本文将为大家分步骤展示[Reddit外部适配器](https://market.link/adapters/21318744-2f78-4eef-bcbc-808608fde675)。 # OAuth是什么? 你上网的时候通常需要证明自己的身份。最简单的证明方式是使用用户名和密码,这也被称为[密码认证或基础认证](https://swoopnow.com/password-authentication/#https://swoopnow.com/password-authentication/)。然而,还有一种方式也可以证明我们的真实身份,那就是让别人来为我们做担保。这就是OAuth的工作原理,它是一种第三方[通证认证](https://www.okta.com/identity-101/what-is-token-based-authentication/),即其中一方为另一方做认证。 OAuth的运行机制是,双方委托第三方通过数字通证的方式证明其中一方的身份。以下这个例子可以简明扼要地概括其精髓: Bob希望从Alice手中获取数据,但不希望把密码交给Alice或暴露自己的身份信息。Bob和Alice有个共同的朋友,Margaret。Margaret跟Bob说她可以给他发一个临时通证,Bob可以用这个通证向Alice获取数据,Alice不需要知道Bob叫什么名字,也不需要获得任何Bob的个人信息。Alice只知道请求数据的人是可以相信的。Margaret借给Bob一个通证从Alice那获取数据,这有点类似你把酒店房卡借给别人。 一旦在系统中添加了OAuth,就多出了一个步骤,即访问所需的数据,因为你得先等待可信第三方响应才能继续下去。基础认证只需输入密码就可以,而OAuth认证则需等待从第三方获得通证。 我们都知道,以太坊(1.0)等区块链的流程是同步执行的,也就是说这类区块链只能同时做一件事,因此等待通证获得API响应的过程就会显得有点笨重。另外,Solidity需要等待通证传回才能调用新的API,这也会造成gas浪费。有一个好办法可以解决这个问题,那就是使用Chainlink外部适配器统一访问链下数据源,这不仅可以加速智能合约的OAuth认证,还可以降低gas成本。 # 在Nodejs中使用OAuth 外部适配器可以实现在Solidity智能合约中完成OAuth认证,我们在开发外部适配器时,首先要决定是自己亲自开发OAuth handler还是试用别人开发的handler。OAuth handler是指一段代码,让我们可以轻松处理登入和登出。绝大多数情况下,如果已经有现成的解决方案,我们就不必重复劳动了。一些平台已经采用了OAuth认证,你一般可以找到现成的OAuth handler。比如,我们找到了这个[非常好用的Reddit handler](https://github.com/feross/reddit/blob/master/index.js),我们可以运行代码查看其功能。 这里有两个主要的函数: ```javascript async _getToken () ``` 以及 ```javascript _makeRequest (method, url, data, token) ``` _getToken()函数的作用是获取通证,_makeRequest函数的作用是向Reddit URL发送最终认证请求以及通证。在这个实现中,这两个函数可以被`_sendRequest`一起调用。 我们可以看到_getToken ()函数实际上是通过基础认证方式与第三方交互的。 ```javascript return new Promise((resolve, reject) => { get.concat({ url: TOKEN_BASE_URL, method: 'POST', form: { grant_type: 'password', username: this.username, password: this.password }, headers: { authorization: `Basic ${Buffer.from(`${this.appId}:${this.appSecret}`).toString('base64')}`, 'user-agent': this.userAgent }, json: true, timeout: REQUEST_TIMEOUT }, (err, res, body) => { if (err) { err.message = `Error getting token: ${err.message}` return reject(err) } ``` _makeRequest ()函数使用的是通证而不是密码。 ```javascript return new Promise((resolve, reject) => { const opts = { url: url, method: method, headers: { authorization: token, 'user-agent': this.userAgent }, timeout: REQUEST_TIMEOUT } ``` 现成的可以拿来用,这点无可厚非,但同时我们也要理解它的运行机制,这样当有需要的时候也能自己动手开发。 现在OAuth的代码已经都完成了,接下来就可以把外部适配器模板中的内容替换掉了!你可以随意选择自己喜欢的适配器,但是我们在这里用的是[Chainlink外部适配器模板](https://github.com/thodges-gh/CL-EA-NodeJS-Template)。如果你之前看过[关于开发外部适配器的文章](https://blog.chain.link/build-and-use-external-adapters/),那么接下来的内容应该对你来说非常简单!我们可以把这些代码全部复制粘贴到我们的外部适配器中,不过更好的方法是直接导入,这样我们就可以把全部精力放在Solidity和智能合约代码上,而不是认证环节。 # Reddit外部适配器 现在OAuth handler设置好了,我们可以把它添加到我们的Chainlink外部适配器中,方法跟其他[Chainlink适配器](https:/docs.chain.link/docs/adapters&quot)完全一样。我们可以将适配器添加到列表中,然后使用OAuth认证开展任何所需的计算任务。如果仔细研究[Reddit外部适配器](https://github.com/tweether-protocol/reddit-cl-ea)的代码,可以看到开发框架跟[index.js](https://github.com/tweether-protocol/reddit-cl-ea/blob/master/index.js)中的完全一样。与[上一篇关于外部适配器的文章](https://blog.chain.link/build-and-use-external-adapters/)一样,我们也只需更新[index.js](https://github.com/tweether-protocol/reddit-cl-ea/blob/master/index.js)中的代码。最大的不同点是我们在这里安装了一个新的包,即Reddit包,代码如下: ```javascript const Reddit = require('reddit') ``` 我们所有的身份认证信息都可以这样添加: ```javascript const reddit = new Reddit({ username: process.env.REDDIT_USER, password: process.env.REDDIT_PASSWORD, appId: process.env.REDDIT_API_KEY, appSecret: process.env.REDDIT_API_SECRET, userAgent: 'tweether', }) ``` 一旦你在Reddit网站[创建了一个APP](https://www.reddit.com/prefs/apps),就会获得REDDIT_API_KEY和REDDIT_API_SECRET,并用于适配器中。我们可以利用外部适配器的许多参数来定制化智能合约发送到Reddit的内容。 ```javascript const customParams = { sr: false, kind: false, resubmit: false, title: false, text: false, endpoint: false, url: false, } ``` 这些定制化参数都可以在[Reddit API文档](https://www.reddit.com/dev/api/)中找到。 我们对模板还做了一个比较大的修改,那就是我们没有用Requester对象发送请求,而是使用了Reddit对象,代码如下: ```javascript reddit .post(endpoint, { sr: sr, kind: kind, resubmit: resubmit, title: title, text: text, url: url, }) .then((response) => { response.json.data.result = response.json.data.id response.json.status = 200 callback(response.json.status, Requester.success(jobRunID, response.json)) }) .catch((error) => { callback(500, Requester.errored(jobRunID, error)) }) ``` 代码写完以后可以来测试一下! 设置四个环境变量,然后运行以下代码: ```shell git clone https://github.com/tweether-protocol/reddit-cl-ea cd reddit-cl-ea yarn yarn start ``` 打开另外一个终端,用以下命令进行测试: ```shell curl -X POST -H "content-type:application/json" "http://localhost:8080/" --data '{ "id": 0, "data": {"title":"HELLO" }}' ``` 你在输出中就可以看到在Reddit上发布的内容了! 如果有时间,你还可以查看[Twitter Chainlink外部适配器](https://market.link/adapters/9ebb251e-1d7c-433d-9835-d771996f5b9c),并根据智能合约的交互情况发布Twitter状态。 以上就是使用OAuth和Reddit外部适配器与智能合约交互的第一步。你需要使用一个安装了外部适配器的节点,并在节点中设置身份认证信息。欢迎大家查看[Chainlink文档 ](https://docs.chain.link/docs),了解如何进行下一步操作。如果你使用OAuth在智能合约中开发出了有趣的应用,请上传至[market.link ](https://market.link/adapters/21318744-2f78-4eef-bcbc-808608fde675),帮助其他人也实现智能合约与链下世界交互。除此之外,你还可以展示你个人的智能合约开发实力。 如果你是一名开发者,并希望快速将智能合约连接至链下数据和系统,请查看[ 我们的开发者文档](https:/docs.chain.link/)并加入我们在[ Discord](https://discordapp.com/invite/aSK4zew)上的技术讨论群。如果你希望透过电话具体讨论集成细节,请[点击此处](https://chainlink.typeform.com/to/gEwrPO)联系我们。 [Website](https://chain.link/) | [Twitter](https://twitter.com/chainlink) |[ Reddit](https://www.reddit.com/r/Chainlink/) | [YouTube](https://www.youtube.com/channel/UCnjkrlqaWEBSnKZQ71gdyFA) | [Telegram](https://t.me/chainlinkofficial) | [Events](https://blog.chain.link/tag/events/) | [GitHub](https://github.com/smartcontractkit/chainlink) | [Price Feeds](https://feeds.chain.link/) | [DeFi](https://defi.chain.link/) [原文链接](https://blog.chain.link/oauth-and-api-authentication-in-smart-contracts-2/)

智能合约中的OAuth和API认证

智能合约中的OAuth和API认证插图

OAuth是主流的API认证和授权方式,用户无须暴露其身份信息即可访问各种网站和应用。乍一看,我们似乎很难从OAuth这样的链下Web2服务中获取数据并上传至链上智能合约。然而,有了Chainlink外部适配器 ,就可以在链下展开复杂的运算,这与基于OAuth的API认证无任何差异。接入外部适配器后,就可以使用OAuth访问更多安全的链下数据源,并轻松实现与链上智能合约的交互。我们可以从Solidity或其他智能合约中调用这些安全的API,访问各种服务并同时保障安全。本文将为大家分步骤展示Reddit外部适配器。

OAuth是什么?

你上网的时候通常需要证明自己的身份。最简单的证明方式是使用用户名和密码,这也被称为密码认证或基础认证。然而,还有一种方式也可以证明我们的真实身份,那就是让别人来为我们做担保。这就是OAuth的工作原理,它是一种第三方通证认证,即其中一方为另一方做认证。

OAuth的运行机制是,双方委托第三方通过数字通证的方式证明其中一方的身份。以下这个例子可以简明扼要地概括其精髓:

Bob希望从Alice手中获取数据,但不希望把密码交给Alice或暴露自己的身份信息。Bob和Alice有个共同的朋友,Margaret。Margaret跟Bob说她可以给他发一个临时通证,Bob可以用这个通证向Alice获取数据,Alice不需要知道Bob叫什么名字,也不需要获得任何Bob的个人信息。Alice只知道请求数据的人是可以相信的。Margaret借给Bob一个通证从Alice那获取数据,这有点类似你把酒店房卡借给别人。

一旦在系统中添加了OAuth,就多出了一个步骤,即访问所需的数据,因为你得先等待可信第三方响应才能继续下去。基础认证只需输入密码就可以,而OAuth认证则需等待从第三方获得通证。

我们都知道,以太坊(1.0)等区块链的流程是同步执行的,也就是说这类区块链只能同时做一件事,因此等待通证获得API响应的过程就会显得有点笨重。另外,Solidity需要等待通证传回才能调用新的API,这也会造成gas浪费。有一个好办法可以解决这个问题,那就是使用Chainlink外部适配器统一访问链下数据源,这不仅可以加速智能合约的OAuth认证,还可以降低gas成本。

在Nodejs中使用OAuth

外部适配器可以实现在Solidity智能合约中完成OAuth认证,我们在开发外部适配器时,首先要决定是自己亲自开发OAuth handler还是试用别人开发的handler。OAuth handler是指一段代码,让我们可以轻松处理登入和登出。绝大多数情况下,如果已经有现成的解决方案,我们就不必重复劳动了。一些平台已经采用了OAuth认证,你一般可以找到现成的OAuth handler。比如,我们找到了这个非常好用的Reddit handler,我们可以运行代码查看其功能。

这里有两个主要的函数:

async _getToken ()

以及

_makeRequest (method, url, data, token)

_getToken()函数的作用是获取通证,_makeRequest函数的作用是向Reddit URL发送最终认证请求以及通证。在这个实现中,这两个函数可以被_sendRequest一起调用。

我们可以看到_getToken ()函数实际上是通过基础认证方式与第三方交互的。

return new Promise((resolve, reject) => {
      get.concat({
        url: TOKEN_BASE_URL,
        method: 'POST',
        form: {
          grant_type: 'password',
          username: this.username,
          password: this.password
        },
        headers: {
          authorization: `Basic ${Buffer.from(`${this.appId}:${this.appSecret}`).toString('base64')}`,
          'user-agent': this.userAgent
        },
        json: true,
        timeout: REQUEST_TIMEOUT
      }, (err, res, body) => {
        if (err) {
          err.message = `Error getting token: ${err.message}`
          return reject(err)
        }

_makeRequest ()函数使用的是通证而不是密码。

return new Promise((resolve, reject) => {
      const opts = {
        url: url,
        method: method,
        headers: {
          authorization: token,
          'user-agent': this.userAgent
        },
        timeout: REQUEST_TIMEOUT
      }

现成的可以拿来用,这点无可厚非,但同时我们也要理解它的运行机制,这样当有需要的时候也能自己动手开发。

现在OAuth的代码已经都完成了,接下来就可以把外部适配器模板中的内容替换掉了!你可以随意选择自己喜欢的适配器,但是我们在这里用的是Chainlink外部适配器模板。如果你之前看过关于开发外部适配器的文章,那么接下来的内容应该对你来说非常简单!我们可以把这些代码全部复制粘贴到我们的外部适配器中,不过更好的方法是直接导入,这样我们就可以把全部精力放在Solidity和智能合约代码上,而不是认证环节。

Reddit外部适配器

现在OAuth handler设置好了,我们可以把它添加到我们的Chainlink外部适配器中,方法跟其他Chainlink适配器完全一样。我们可以将适配器添加到列表中,然后使用OAuth认证开展任何所需的计算任务。如果仔细研究Reddit外部适配器的代码,可以看到开发框架跟index.js中的完全一样。与上一篇关于外部适配器的文章一样,我们也只需更新index.js中的代码。最大的不同点是我们在这里安装了一个新的包,即Reddit包,代码如下:

const Reddit = require('reddit')

我们所有的身份认证信息都可以这样添加:

const reddit = new Reddit({
  username: process.env.REDDIT_USER,
  password: process.env.REDDIT_PASSWORD,
  appId: process.env.REDDIT_API_KEY,
  appSecret: process.env.REDDIT_API_SECRET,
  userAgent: 'tweether',
})

一旦你在Reddit网站创建了一个APP,就会获得REDDIT_API_KEY和REDDIT_API_SECRET,并用于适配器中。我们可以利用外部适配器的许多参数来定制化智能合约发送到Reddit的内容。

const customParams = {
  sr: false,
  kind: false,
  resubmit: false,
  title: false,
  text: false,
  endpoint: false,
  url: false,
}

这些定制化参数都可以在Reddit API文档中找到。

我们对模板还做了一个比较大的修改,那就是我们没有用Requester对象发送请求,而是使用了Reddit对象,代码如下:

reddit
    .post(endpoint, {
      sr: sr,
      kind: kind,
      resubmit: resubmit,
      title: title,
      text: text,
      url: url,
    })
    .then((response) => {
      response.json.data.result = response.json.data.id
      response.json.status = 200
      callback(response.json.status, Requester.success(jobRunID, response.json))
    })
    .catch((error) => {
      callback(500, Requester.errored(jobRunID, error))
    })

代码写完以后可以来测试一下!

设置四个环境变量,然后运行以下代码:

git clone https://github.com/tweether-protocol/reddit-cl-ea
cd reddit-cl-ea
yarn
yarn start

打开另外一个终端,用以下命令进行测试:

curl -X POST -H "content-type:application/json" "http://localhost:8080/" --data '{ "id": 0, "data": {"title":"HELLO" }}'

你在输出中就可以看到在Reddit上发布的内容了!

如果有时间,你还可以查看Twitter Chainlink外部适配器,并根据智能合约的交互情况发布Twitter状态。

以上就是使用OAuth和Reddit外部适配器与智能合约交互的第一步。你需要使用一个安装了外部适配器的节点,并在节点中设置身份认证信息。欢迎大家查看Chainlink文档 ,了解如何进行下一步操作。如果你使用OAuth在智能合约中开发出了有趣的应用,请上传至market.link ,帮助其他人也实现智能合约与链下世界交互。除此之外,你还可以展示你个人的智能合约开发实力。

如果你是一名开发者,并希望快速将智能合约连接至链下数据和系统,请查看 我们的开发者文档并加入我们在 Discord上的技术讨论群。如果你希望透过电话具体讨论集成细节,请点击此处联系我们。

Website | Twitter | Reddit | YouTube | Telegram | Events | GitHub | Price Feeds | DeFi

原文链接

区块链技术网。

  • 发表于 2020-11-11 13:32
  • 阅读 ( 1789 )
  • 学分 ( 10 )
  • 分类:预言机

评论