【发布时间】:2022-12-22 12:41:26
【问题描述】:
当我尝试注销时,我在使用简单的 JWT 时遇到了问题。我被告知注销时,必须删除 cookie 并且必须将刷新令牌列入黑名单!
除注销外,所有先前的身份验证步骤(注册、登录)都按预期工作。
登记
登录
登出
在上面的捕获中,我得到了 401 unauthorized。 cookie 似乎已按预期删除。
正如我发现的 Q/As 所建议的那样,我尝试了以下方法:
- 打印异常,但除了 401 错误之外什么也没有显示。
- 添加授权标头和“Bearer”与“JWT”之间的互换。
- 修改settings.py,应用简单的jwt认证码模板。我的代码如下:
设置.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer', 'JWT',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'email',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
}
AUTH_USER_MODEL = 'users.CustomUser'
CORS_ALLOWED_ORIGINS = [
"http://127.0.0.1:3000",
"http://localhost:3000",
"http://127.0.0.1:8000",
"http://localhost:8000",
]
序列化器.py
class LogoutSerializer(serializers.Serializer):
refresh = serializers.CharField()
default_error_messages = {
'bad_token': _('Token is invalid or expired')
}
def validate(self, attrs):
self.token = attrs['refresh']
return attrs
def save(self, **kwargs):
try:
RefreshToken(self.token).blacklist()
except TokenError:
self.fail('bad_token')
except Exception as e:
print('\nException in logging out:', e)
视图.py
class RegisterView(APIView):
permission_classes = [AllowAny]
def post(self, request, format='json'):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = CustomUser.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed('Incorrect password!')
payload = {
# 'id': user.id,
'email': user.email,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
response = Response({'message': 'success'})
response.set_cookie(key='jwt', value=token, httponly=True)
response.data = {
'jwt': token
}
return response
class LogoutView(generics.GenericAPIView):
serializer_class = LogoutSerializer
permission_classes = (permissions.IsAuthenticated,)
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_204_NO_CONTENT)
用户/urls.py
urlpatterns = [
path('', UserList.as_view()),
path('register', RegisterView.as_view()),
path('login', LoginView.as_view()),
path('user', UserView.as_view()),
path('logout', LogoutView.as_view()),
]
模型.py
class CustomUserManager(BaseUserManager):
def create_superuser(self, email, password=None):
if password is None:
raise TypeError('Password should not be none')
user = self.create_user(email, password)
user.is_superuser = True
user.is_staff = True
if user.is_superuser is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if user.is_staff is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
user.save()
return user
def create_user(self, email, password=None):
if email is None:
raise TypeError('Users should have a Email')
email = self.normalize_email(email)
user = self.model(email=email)
user.set_password(password)
user.save()
return user
AUTH_PROVIDERS = {'facebook': 'facebook', 'google': 'google',
'twitter': 'twitter', 'email': 'email'}
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
about = models.TextField(_(
'about'), max_length=500, blank=True)
auth_provider = models.CharField(
max_length=255, blank=False,
null=False, default=AUTH_PROVIDERS.get('email'))
USERNAME_FIELD = 'email'
# REQUIRED_FIELDS = ['username']
objects = CustomUserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}
上面的代码来自几个教程,但不知何故没有像他们应该的那样工作! 你能建议我解决这个问题的方法吗?谢谢!
【问题讨论】:
-
你能解决你的问题吗?还有其他问题,为什么在 LoginView 中使用 'user = CustomUser.objects.filter' 而不是
django.contrib.auth.authenticate()?如果您使用的是ModelBackend,这最后会检查密码。 -
@Jony_23 是的,我在后端解决了这个问题。 CustomUser 模型有问题
-
那太棒了!我知道,我在自定义用户模型方面遇到了很多问题。
-
你做了什么来解决这个问题?
标签: django-rest-framework django-rest-framework-simplejwt