我目前正在开发一个 Web 应用程序,该应用程序使用 Django 作为后端、Django Rest Framework 作为 API、React 作为前端、PostgreSQL 作为数据库。对于用户身份验证,我使用了 SimpleJWT。但是,我遇到了一个问题,我可以通过前端创建用户帐户,但无法使用新创建的帐户登录。控制台中出现一条错误消息,用户信息存在于数据库中。但是,我仍然可以通过前端和 Django Rest Framework 使用不久前创建的几个帐户(来自同一数据库表的所有帐户)登录。
我在 Django 上不断收到此错误:
错误中每次
(user_id)
的括号可能不同
IntegrityError at /api/token/
insert or update on table "token_blacklist_outstandingtoken" violates foreign key constraint "token_blacklist_outs_user_id_83bc629a_fk_auth_user"
DETAIL: Key (user_id)=(4) is not present in table "auth_user".
这是我的数据库表,我可以通过前端和Rest框架成功登录前3个帐户
settings.py(仅 simpleJWT 部分):
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=30),
"REFRESH_TOKEN_LIFETIME": timedelta(days=90),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
"UPDATE_LAST_LOGIN": True,
# FOR SECURITY REASON (ABOVE)
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
"VERIFYING_KEY": "",
"AUDIENCE": None,
"ISSUER": None,
"JSON_ENCODER": None,
"JWK_URL": None,
"LEEWAY": 0,
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
"USER_ID_FIELD": "id",
"USER_ID_CLAIM": "user_id",
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
"TOKEN_TYPE_CLAIM": "token_type",
"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
"JTI_CLAIM": "jti",
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
"TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
"TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
"TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
"TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
"SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
"SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}
api/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
username = models.CharField(max_length=100)
email = models.EmailField(max_length=100, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
api/序列化器.py
from api.models import CustomUser
from rest_framework import serializers
from django.contrib.auth.password_validation import validate_password
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'username', 'email')
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username
token['email'] = user.email
return token
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True, required=True, validators=[validate_password])
confirmed_password = serializers.CharField(write_only=True, required=True)
class Meta:
model = CustomUser
fields = ('email', 'username', 'password', 'confirmed_password')
def validate(self, attrs):
if attrs['password'] != attrs['confirmed_password']:
raise serializers.ValidationError(
{"password": "Password fields didn't match."})
return attrs
def create(self, validated_data):
user = CustomUser.objects.create(
username=validated_data['username'],
email=validated_data['email']
)
user.set_password(validated_data['password'])
user.save()
return user
api/urls.py
from django.urls import path
from . import views
from .views import MyTokenObtainPairView
from rest_framework_simplejwt.views import(
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('', views.getRoutes),
path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('register/', views.RegisterView.as_view(), name='auth_register'),
]
api/views.py
from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import generics
from api.models import CustomUser
from rest_framework.permissions import AllowAny
from .serializers import MyTokenObtainPairSerializer, RegisterSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
class RegisterView(generics.CreateAPIView):
queryset = CustomUser.objects.all()
permission_classes = (AllowAny,)
serializer_class = RegisterSerializer
@api_view(['GET'])
def getRoutes(request):
routes = [
'/api/token',
'/api/register',
'/api/token/refresh'
]
return Response(routes)
您正在将帐户保存到新的自定义模型
CusomUser
,尽管令牌正在使用内置的 auth_user 模型进行检查,因此会出现错误DETAIL: Key (user_id)=(4) is not present in table "auth_user".
,尝试打开auth_user
表,您很可能只会找到您可以使用 3 个帐户登录,因此可以使用 auth_user
模型作为用户的主要模型并开始保存到该模型,或者更改令牌设置以检查 CustomUser
模型。