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),方便後面登入。
登入功能:
取得當前使用者資料:
登出當前使用者:
取得當前使用者資料(登出後):
然後從 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、Payload 與 Signature 以.
串連成 JWT,其實不難看出 JWT 並沒有資料保密的功能,所以 Payload 不會放入過於機密的資訊,JWT 所做到的是容易解析認證資訊,並透過驗證簽章檢查 JWT 是否被竄改過。
很不幸, strawberry_django 與 strawberry 目前沒有可用的相關套件:
所以可能比較好的方式是參考上面兩個套件,自行實作自己需要的功能。
這次修改內容可以參考 Git commit: