我是一名学生,正在尝试自学 JWT 身份验证。我创建了一个基本的登录页面,登录后用户应该看到一个欢迎页面,上面写着“Welcome {username}”。 然而,即使登录后,欢迎页面仍显示
欢迎光临 获取/欢迎/ HTTP 401 未经授权 允许:获取、选项 内容类型:application/json 变化:接受 WWW-身份验证:承载领域=“api”
{ "detail": "未提供身份验证凭据。" }
我的代码如下所示:
views.py
from django.http import JsonResponse
from django.shortcuts import render, redirect
from loginapp.models import User
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate
from rest_framework_simplejwt.authentication import JWTAuthentication
from django.urls import reverse
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print("Username:", username)
print("Password:", password)
user = User.objects.filter(username=username).first()
#user = authenticate(username=username, password=password)
if user is not None and user.password == password:
refresh = RefreshToken.for_user(user)
token = str(refresh.access_token)
response = JsonResponse({'message': 'Login successful'})
response['Authorization'] = f'Bearer {token}'
return response
else:
return JsonResponse({'error_message': 'Invalid username or password.'}, status=400)
else:
return render(request, 'login.html')
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def welcome(request):
username = request.user.username
return Response({'message': f'Welcome, {username}!'})
我的 urls.py 看起来像这样:
from django.urls import path
from loginapp import views
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.views import TokenRefreshView
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.login, name='login'),
path('welcome/',views.welcome, name='welcome'),
#path('welcome/<str:username>/', views.welcome, name='welcome'),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
我的登录.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<div id="error-message"></div>
<form id="loginForm">
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password"><br>
<button type="submit">Login</button>
</form>
<script>
document.getElementById("loginForm").addEventListener("submit", function(event) {
event.preventDefault();
fetch("/", {
method: "POST",
body: new FormData(document.getElementById("loginForm"))
})
.then(response => {
if (response.ok) {
const token = response.headers.get('Authorization').split(' ')[1];
localStorage.setItem("jwtToken", token);
window.location.href = "/welcome";
} else {
return response.json();
}
})
.then(data => {
if (data.error_message) {
document.getElementById("error-message").innerText = data.error_message;
}
})
.catch(error => {
console.error("Error:", error);
});
});
</script>
</body>
</html>
我的设置.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'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,
'UPDATE_LAST_LOGIN': True,
}
有人可以指出问题可能出现在哪里吗? 我正在使用 MySQL 数据库,我从中查询用户名。
我尝试更改settings.py ACCESS_TOKEN_LIFETIME,但即使现在已经是60分钟了,错误仍然存在。
您返回了 JsonResponse,其中包含访问令牌,但之后您必须手动将令牌值添加到下一个请求标头中。
response = JsonResponse({'message': 'Login successful'})
response['Authorization'] = f'Bearer {token}'
return response
此代码将无法正常工作,因为每个请求和响应都被视为独立的。您的下一个请求将不包含授权令牌,这会导致
401 Unauthorized
错误。
我的建议是仅返回访问令牌,而不设置用于响应的
Authorization
键。
return JsonResponse({'message': 'Login successful', 'token': token})
您可以通过将其保存在前端的 cookie 或本地存储中来使用此令牌。