Day19 - 【概念篇】OAuth flows: Device Code(1)

本系列文之後也会置於个人网站



      +----------+                                +----------------+
      |          |>---(A)-- Client Identifier --->|                |
      |          |                                |                |
      |          |<---(B)-- Device Code,      ---<|                |
      |          |          User Code,            |                |
      |  Device  |          & Verification URI    |                |
      |  Client  |                                |                |
      |          |  [polling]                     |                |
      |          |>---(E)-- Device Code       --->|                |
      |          |          & Client Identifier   |                |
      |          |                                |  Authorization |
      |          |<---(F)-- Access Token      ---<|     Server     |
      +----------+   (& Optional Refresh Token)   |                |
            v                                     |                |
            :                                     |                |
           (C) User Code & Verification URI       |                |
            :                                     |                |
            v                                     |                |
      +----------+                                |                |
      | End User |                                |                |
      |    at    |<---(D)-- End user reviews  --->|                |
      |  Browser |          authorization request |                |
      +----------+                                +----------------+

                    Figure 1: Device Authorization Flow

   The device authorization flow illustrated in Figure 1 includes the
   following steps:

   (A)  The client requests access from the authorization server and
        includes its client identifier in the request.

   (B)  The authorization server issues a device code and an end-user
        code and provides the end-user verification URI.

   (C)  The client instructs the end user to use a user agent on another
        device and visit the provided end-user verification URI.  The
        client provides the user with the end-user code to enter in
        order to review the authorization request.

Device Code Flow这个与前面几个特别不一样。在之前,以往都是从登入开始,然後跳转页面回到App(Client)。也就是通常先有的是前端通讯,然後才是後端通信。

这次不太同,开始不再是由资源拥有者发起,更像是由客户端开始。甚至登入的方法与客户端还没有特别强烈的关联。大致流程说明如下:

  1. 客户端应用发起。向授权服务器取得device_codeuser_code
  2. 客户端应用将user_code交给资源拥有者。
  3. 资源拥有者透过某个端点(endpoint)与user_code进行授权。
  4. 客户端应用透过device_code询问授权服务器是某有人授权。

在这里device_code有点更像是传统的sessionuser_code更像是之前的特殊密码。

硬要比喻的话,就像是有一个充满智慧的门,就先叫做「魔门」吧!这个魔门不但聪明还会识别人脸。它知道未来有一天,一定会有一个人来开启它这扇门,但他不知道是谁。於是他把一段咒语--「魔门阿!魔门!谁是世界上最安全的锁」--告诉管家。如果有一天有一个人将这个咒语告诉了管家,那就请管家将这个人的脸纪录下来,并告诉魔门。当这个人走到魔门前面的时候,魔门就认得这张人脸,也就会自动开门了。

怕有人不知道。「魔镜」的故事听过吧XD

虽然这个比喻并不完全匹配,但是这里的「魔镜」有点像是客户端;「管家」仍然是授权服务器。与之前几个流程相比,有点像是反过来走。

事前准备 - 建立一个新的Client example-device-app

由於OAuth Playground和OAuth.tools都不太能很好的用来理解这个模式。所以这一个会分成两个部分介绍,除了实际走走上面提到的流程,还会在实际开发一个简易的客户端。如此,希望能够使各位能够更明白Device Code Flow。

那麽就先来再建立一个客户端。

尽管用之前的「oauth_tools」或是调整「my-quick-start-app」也可以。不过还是从头来一遍吧!

  • Client ID: example-device-app
  • Root URL: http://localhost:4200/

虽然这次Root URL并不是很重要,但还是填上与「my-quick-start-app」相同的值吧!

然後注意这次的Access Type需要选择confidential并且将Oauth 2.0 Device Authorization Grant啓用。

然後先将 Credentials > Secret 记下来。

这麽一来前置工作就算是准备好了。

取得device_codeuser_code

这次要用HTTP POST的方法打http://localhost:8080/auth/realms/quick-start/device这个端点。

这次需要配合 Client Credentials 模式。所以不但要给client_id,也需要client_secretclient_secret填入刚刚所记下来的secret

  • client_id: example-device-app
  • client_secret: <方才记录下来的secret>

在送出request後会得到一些资讯。

{
    "device_code": "boTQ6vd49RXTOYOb7dwXBCpHYskzOjXvDPjkXxniMN0",
    "user_code": "HZYO-ROXJ",
    "verification_uri": "http://localhost:8080/auth/realms/quick-start/device",
    "verification_uri_complete": "http://localhost:8080/auth/realms/quick-start/device?user_code=HZYO-ROXJ",
    "expires_in": 600,
    "interval": 5
}

其中最重要的是device_codeuser_codeverification_uri

到这边算是初步完成了,但你可以先透过token_endpoint,也就是http://localhost:8080/auth/realms/quick-start/protocol/openid-connect/token这个端点确定一下。

除了需要给与device_code以外,还需要将grant_type改成urn:ietf:params:oauth:grant-type:device_code

  • grant_type: urn:ietf:params:oauth:grant-type:device_code
  • device_code: <方才取得的device_code>

现在,你应该会得到仍未有人登入授权。

魔门 真是孤独阿~

{
    "error": "authorization_pending",
    "error_description": "The authorization request is still pending"
}

进行登入授权

接着,同样透过刚刚知道的端点 verification_uri 登入。浏览器开啓 http://localhost:8080/auth/realms/quick-start/device ,并输入同样刚才得到的user_code:

或者是一个特殊的端点http://localhost:8080/auth/realms/quick-start/device?user_code=<user_code>。但总之登入後的是一个授权画面。

在看下Yes允许授权後,提示的是登入成功,我们可以回到我们的应用。

取得存取权杖

同样在尝试取得一次存取权杖看看:

  • grant_type: urn:ietf:params:oauth:grant-type:device_code
  • device_code: <方才取得的device_code>

这次我们就可以取得存取权杖了~

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ4VXh6WGR4UWpFNDNIZGdYbXJkUjBQZWxXN1ZoZWowbGRkR2NhN0VubXpZIn0.eyJleHAiOjE2MzI1Nzg5NTQsImlhdCI6MTYzMjU3ODY1NCwiYXV0aF90aW1lIjoxNjMyNTc3NTIxLCJqdGkiOiI5YTBhYTdkZi02NmEyLTRlMDgtYmZmNS05MjU2NDZlYmM1MTkiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvcXVpY2stc3RhcnQiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMzQ1YjFiY2EtOTgwNS00YjRiLWEwZjgtZGEyYzcwMTc2YzU5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZXhhbXBsZS1kZXZpY2UtYXBwIiwic2Vzc2lvbl9zdGF0ZSI6ImFmODhlZmZiLTVmNDgtNDgxZi04YWI2LTQ5MGRhMjY2YzY1ZCIsImFjciI6IjAiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo0MjAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXF1aWNrLXN0YXJ0Iiwib2ZmbGluZV9hY2Nlc3MiLCJxdWljay1zdGFydC1leGFtcGxlLXJvbGUxIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQiLCJ3ZWJzaXRlIjoiaHR0cHM6Ly9ib2IuaWQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ2VuZGVyIjoibWFuIiwibmFtZSI6IkJvYiBMZWUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJib2IiLCJnaXZlbl9uYW1lIjoiQm9iIiwiZmFtaWx5X25hbWUiOiJMZWUiLCJlbWFpbCI6ImJvYkBmYWtlLmVtYWlsIn0.aPYPiG9icNnrxmmRUPoN_rf2eLhkprK7haXD9M6CpGRAHnjyzOkH1H2an3Au2I4LgFX7fdO95E5mF7NZ4gw-5SFe9Wof3Toe8araIQepurJXMd9Vx9Y6cO-htha796rkpUq2XNkcBLRHl9bN2zN3-2VM1X1pBqQPtDPeGckkp_2KH8u8n9UPxdq_lD-FZ_3-YzQav1RTs81QkxEBTn8Un7mzgRjdsmIkEJKYQqnhg86Xkw_bAGz-F-nDoj1XtHqjSIk_1EZ9brcgi05us-9ZL0tBViycQRCXEgJjq555omxh1XgjjuC_KPzA3y7hTTE75ZvO-3rc0sVy1DC-1AEtbg",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0NjUwNDBkYi1lNGJkLTRiYTYtOWM2Ny02ZWYxZGJmMmUxOWYifQ.eyJleHAiOjE2MzI1ODA0NTQsImlhdCI6MTYzMjU3ODY1NCwianRpIjoiZGI3NTBjOTMtODg3Mi00YmUxLTk3YWUtMmU2MTMxNzNjMDU2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL3F1aWNrLXN0YXJ0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL3F1aWNrLXN0YXJ0Iiwic3ViIjoiMzQ1YjFiY2EtOTgwNS00YjRiLWEwZjgtZGEyYzcwMTc2YzU5IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6ImV4YW1wbGUtZGV2aWNlLWFwcCIsInNlc3Npb25fc3RhdGUiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQiLCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQifQ.1NGocwCZbpT-OjKnVj420Vql1_C3iwcZavuwJEk2sk0",
    "token_type": "Bearer",
    "not-before-policy": 1631743594,
    "session_state": "af88effb-5f48-481f-8ab6-490da266c65d",
    "scope": "email profile"
}

参考资料


<<:  Day 20 TensorFlowJS

>>:  [DAY 20]用bot打出色色柴犬counter牌(更新句子相似度判断)

滑鼠键盘的无线世界 - Uifying /蓝芽

朋友送了一组键盘滑鼠.Logitech 键盘yr0009 & 滑鼠M215 想要滑鼠放家里用...

Day 27 | 数字辨识 - 进行预测

回到MNIST手写数字辨识的单元,前面已经完成了模型的建立及训练,也学会如何印出和判读训练过程,那麽...

身为面试官,在面试中如何在有限了时间解应徵者

怎麽样确定这个人就对的那个人?前一篇有提到面试官可以怎麽提问技术题,那麽要确认应徵者的人格特质可以从...

Rails has_many

has_many 的设定 class_name 可以变更关联的类别名称,例如以下新增了paid_at...

Binary Search

二元搜寻BigO(log n) 相较於线性搜寻时间复杂度实在好太多 必须是被排序好的 由於每次对半砍...