iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0

strawberry_django 內建基於 Cookie 與 Session 的登入、登出的變更功能和取得當前使用者的查詢功能。

下面我們就試著加入這些功能:

# server/app/authentication/graph/queries.py
import strawberry
import strawberry_django
+import strawberry_django.auth

from server.app.authentication.graph import types as auth_types

__all__ = ("Query",)

@strawberry.type
class Query:
    users: list[auth_types.User] = strawberry_django.field()
+   me: auth_types.User | None = strawberry_django.auth.current_user()  # type: ignore
# server/app/authentication/graph/mutations.py
# ... 省略

@strawberry.type
class Mutation:
		# ... 省略
+   login: auth_types.User = strawberry_django.auth.login()  # type: ignore
+   logout: bool = strawberry_django.auth.logout()  # type: ignore

可以先在 Django admin 的頁面上找ㄧ個使用者改密碼,或是使用註冊帳號變更功能(userRegister),方便後面登入。

登入功能:

https://ithelp.ithome.com.tw/upload/images/20231008/20161957BfbhWVQrnE.png

取得當前使用者資料:

https://ithelp.ithome.com.tw/upload/images/20231008/20161957Y3UtOgLMwf.png

登出當前使用者:

https://ithelp.ithome.com.tw/upload/images/20231008/20161957POrcZZkGAg.png

取得當前使用者資料(登出後):

https://ithelp.ithome.com.tw/upload/images/20231008/201619578P80ij6TCb.png

然後從 strawberry_django 原始碼來看看,如何在伺服器端拿到登入裝態與使用者物件:

# strawberry_django/auth/queries.py
from strawberry.types import Info  # 這是補充資訊,原始碼沒有這行。

def resolve_current_user(info: Info):
    if not info.context.request.user.is_authenticated:
        return None
    return info.context.request.user

Cookie 與 Session 的認證是帶狀態的認證,Cookie 會儲存 Session ID,用來傳遞到伺服器端來找到對應的 Session 檢查認證,但是這種認證有一些缺點,像是使用 Cookie 使得跨站或是無法使用 Cookie 的應用的認證變得困難,以及 Session 在應用變大的時候擴充會是個挑戰。

所以可以將認證改成使用基於權杖(Token)的認證方式,推薦使用 JWT(JSON Web Token),這種認證方式是將認證資訊(Token)在每次請求時放到 HTTP Header 的Authorization欄位中,權杖是存在客戶端的,來達到無狀態的認證,過去的基於權杖的認證可能 Token 會是一串亂碼或是加密資訊的字串,亂碼的 Token 可能在資料庫會對應到某個使用者,所以每次請求都要去資料庫查詢,加密的 Token 則是需要運算資源解密來取得認證資訊,並且可能各家的規則都不一樣,而 JWT 是一個有一個開放的標準 RFC 7519 所以實作幾乎大同小異,JWT 主要會有三個部分:

  • Header:紀錄 JWT 的使用哪種簽章演算法與權杖類型等資訊,JSON 格式以 Base64Url 編碼的字串。
  • Payload:認證資料,可能會放 User ID、期限以及其他資訊 [1],JSON 格式以 Base64Url 編碼的字串。
  • Signature:簽章,將 Header 與 Payload 組成一個訊息字串,訊息字串與一個伺服器端私鑰傳入 Header 指定簽章演算法,產出驗證簽章的字串

Header、Payload 與 Signature 以.串連成 JWT,其實不難看出 JWT 並沒有資料保密的功能,所以 Payload 不會放入過於機密的資訊,JWT 所做到的是容易解析認證資訊,並透過驗證簽章檢查 JWT 是否被竄改過。

很不幸, strawberry_django 與 strawberry 目前沒有可用的相關套件:

  • Strawberry Django JWT [2]:已經不再更新。
  • Strawberry-django Auth [3]:看起來還有蠻多問題需要解決。

所以可能比較好的方式是參考上面兩個套件,自行實作自己需要的功能。

這次修改內容可以參考 Git commit:

參考資料


上一篇
Day 22:Strawberry Django Relay
下一篇
Day 24:Strawberry Django 權限
系列文
Django 與 Strawberry GraphQL:探索現代 API 開發之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言