This commit is contained in:
ddrwode
2026-02-25 19:10:13 +08:00
parent a315e5f2e1
commit 42b68ededd
6 changed files with 19 additions and 36 deletions

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
认证 API登录无需 token 认证 API登录无需 Authorization
""" """
import uuid import uuid
@@ -15,14 +15,14 @@ from server.serializers import LoginSerializer
@api_view(["POST"]) @api_view(["POST"])
@authentication_classes([]) # 登录接口不校验 Cookie token避免未带 Cookie 时被默认权限判为 403 @authentication_classes([]) # 登录接口不校验 Authorization
@permission_classes([AllowAny]) @permission_classes([AllowAny])
def login(request): def login(request):
""" """
登录接口(支持 JSON 和 form-data 登录接口(支持 JSON 和 form-data
- 校验用户名/密码 - 校验用户名/密码
- 生成 token写入数据库 - 生成 token写入数据库
- 通过 Set-Cookie 返回 auth_token前端后续请求自动携带 - 返回 token前端可放到 Authorization 请求头)
- 下一次登录会生成新 token旧 token 自动失效 - 下一次登录会生成新 token旧 token 自动失效
""" """
ser = LoginSerializer(data=request.data) ser = LoginSerializer(data=request.data)
@@ -40,12 +40,4 @@ def login(request):
defaults={"token": token}, defaults={"token": token},
) )
resp = Response({"token": token}) return Response({"token": token})
resp.set_cookie(
key="auth_token",
value=token,
httponly=True,
max_age=365 * 24 * 60 * 60,
samesite="Lax",
)
return resp

View File

@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
DRF 自定义认证后端:从 Cookie 中读取 auth_token 校验 DRF 自定义认证后端:只要请求头包含 Authorization 即视为已认证
""" """
from rest_framework.authentication import BaseAuthentication from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class TokenUser: class TokenUser:
@@ -17,22 +16,17 @@ class TokenUser:
return self.username return self.username
class CookieTokenAuthentication(BaseAuthentication): class HeaderAuthorizationAuthentication(BaseAuthentication):
""" """仅要求请求头中存在 Authorization 字段。"""
从请求 Cookie 中读取 auth_token查数据库校验。
"""
def authenticate(self, request): def authenticate(self, request):
token = request.COOKIES.get("auth_token") if "HTTP_AUTHORIZATION" not in request.META:
if not token: return None # 未携带 Authorization交给权限类处理
return None # 未携带 token交给权限类处理
# 延迟导入避免循环依赖 # 只要求字段存在,不校验值内容。
from server.models import AuthToken auth_value = request.headers.get("Authorization", "")
return (TokenUser("authorization_header_user"), auth_value)
try:
row = AuthToken.objects.get(token=token)
except AuthToken.DoesNotExist:
raise AuthenticationFailed("登录已失效,请重新登录")
return (TokenUser(row.username), token) # 兼容旧配置名
CookieTokenAuthentication = HeaderAuthorizationAuthentication

View File

@@ -52,7 +52,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# ─── DRF ─── # ─── DRF ───
REST_FRAMEWORK = { REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [ "DEFAULT_AUTHENTICATION_CLASSES": [
"server.core.authentication.CookieTokenAuthentication", "server.core.authentication.HeaderAuthorizationAuthentication",
], ],
"DEFAULT_PERMISSION_CLASSES": [ "DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated", "rest_framework.permissions.IsAuthenticated",

BIN
下载 (1).png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
下载.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,20 +1,17 @@
import requests import requests
url = "http://8.137.99.82:9000/api/auth/login" url = "http://8.137.99.82:9000/api/accounts"
payload={} payload={}
files=[
]
headers = { headers = {
# 'Authorization': '082af0d858ea4d23a905c82bab753d15',
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)', 'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
'Accept': '*/*', 'Accept': '*/*',
'Host': '8.137.99.82:9000', 'Host': '8.137.99.82:9000',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'multipart/form-data; boundary=--------------------------967987379917827495982839', 'Cookie': 'auth_token=082af0d858ea4d23a905c82bab753d15'
'Cookie': 'auth_token=c0ceff1a701e49538965813027f80edb'
} }
response = requests.request("POST", url, headers=headers, data=payload, files=files) response = requests.request("GET", url, headers=headers, data=payload)
print(response.text) print(response.text)