ha'ha
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
认证 API:登录(无需 token)。
|
||||
认证 API:登录(无需 Authorization)。
|
||||
"""
|
||||
import uuid
|
||||
|
||||
@@ -15,14 +15,14 @@ from server.serializers import LoginSerializer
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
@authentication_classes([]) # 登录接口不校验 Cookie token,避免未带 Cookie 时被默认权限判为 403
|
||||
@authentication_classes([]) # 登录接口不校验 Authorization
|
||||
@permission_classes([AllowAny])
|
||||
def login(request):
|
||||
"""
|
||||
登录接口(支持 JSON 和 form-data):
|
||||
- 校验用户名/密码
|
||||
- 生成 token,写入数据库
|
||||
- 通过 Set-Cookie 返回 auth_token,前端后续请求自动携带
|
||||
- 返回 token(前端可放到 Authorization 请求头)
|
||||
- 下一次登录会生成新 token,旧 token 自动失效
|
||||
"""
|
||||
ser = LoginSerializer(data=request.data)
|
||||
@@ -40,12 +40,4 @@ def login(request):
|
||||
defaults={"token": token},
|
||||
)
|
||||
|
||||
resp = Response({"token": token})
|
||||
resp.set_cookie(
|
||||
key="auth_token",
|
||||
value=token,
|
||||
httponly=True,
|
||||
max_age=365 * 24 * 60 * 60,
|
||||
samesite="Lax",
|
||||
)
|
||||
return resp
|
||||
return Response({"token": token})
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
DRF 自定义认证后端:从 Cookie 中读取 auth_token 校验。
|
||||
DRF 自定义认证后端:只要请求头包含 Authorization 即视为已认证。
|
||||
"""
|
||||
from rest_framework.authentication import BaseAuthentication
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
|
||||
|
||||
class TokenUser:
|
||||
@@ -17,22 +16,17 @@ class TokenUser:
|
||||
return self.username
|
||||
|
||||
|
||||
class CookieTokenAuthentication(BaseAuthentication):
|
||||
"""
|
||||
从请求 Cookie 中读取 auth_token,查数据库校验。
|
||||
"""
|
||||
class HeaderAuthorizationAuthentication(BaseAuthentication):
|
||||
"""仅要求请求头中存在 Authorization 字段。"""
|
||||
|
||||
def authenticate(self, request):
|
||||
token = request.COOKIES.get("auth_token")
|
||||
if not token:
|
||||
return None # 未携带 token,交给权限类处理
|
||||
if "HTTP_AUTHORIZATION" not in request.META:
|
||||
return None # 未携带 Authorization,交给权限类处理
|
||||
|
||||
# 延迟导入避免循环依赖
|
||||
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
|
||||
|
||||
@@ -52,7 +52,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
# ─── DRF ───
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||
"server.core.authentication.CookieTokenAuthentication",
|
||||
"server.core.authentication.HeaderAuthorizationAuthentication",
|
||||
],
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.IsAuthenticated",
|
||||
|
||||
BIN
下载 (1).png
Normal file
BIN
下载 (1).png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
11
测试/test.py
11
测试/test.py
@@ -1,20 +1,17 @@
|
||||
import requests
|
||||
|
||||
url = "http://8.137.99.82:9000/api/auth/login"
|
||||
url = "http://8.137.99.82:9000/api/accounts"
|
||||
|
||||
payload={}
|
||||
files=[
|
||||
|
||||
]
|
||||
headers = {
|
||||
# 'Authorization': '082af0d858ea4d23a905c82bab753d15',
|
||||
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
|
||||
'Accept': '*/*',
|
||||
'Host': '8.137.99.82:9000',
|
||||
'Connection': 'keep-alive',
|
||||
'Content-Type': 'multipart/form-data; boundary=--------------------------967987379917827495982839',
|
||||
'Cookie': 'auth_token=c0ceff1a701e49538965813027f80edb'
|
||||
'Cookie': 'auth_token=082af0d858ea4d23a905c82bab753d15'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload, files=files)
|
||||
response = requests.request("GET", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
Reference in New Issue
Block a user