我使用 django rest_framework_simplejwt 包来生成 JWT 令牌并将它们设置在带有 Httponly 标志的可浏览 cookie 中。在 Django 方面,它工作得很好,但在 React 方面,它工作得并不完美。我读了有关这样的问题有许多答案这个和这个,但他们并没有解决我的问题呢。请帮助我理解我错在哪里。
Django边
视图.py
from rest_framework_simplejwt.views import TokenObtainPairView
from django.conf import settings
from rest_framework import status
from rest_framework_simplejwt.exceptions import TokenError,\
InvalidToken
from rest_framework.response import Response
class MyTokenObtainPairView(TokenObtainPairView):
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
except TokenError as e:
raise InvalidToken(e.args[0])
# set access token in browser with Httponly cookie.
res = Response(serializer.validated_data, status=status.HTTP_200_OK)
access_token = serializer.validated_data['access']
res.set_cookie("access_token", access_token, max_age=settings.SIMPLE_JWT.get('ACCESS_TOKEN_LIFETIME').total_seconds(),samesite='Lax',secure=False, httponly=True)
return res
身份验证.py
from rest_framework_simplejwt.authentication import JWTAuthentication
from django.conf import settings
class CookieHandlerJWTAuthentication(JWTAuthentication):
def authenticate(self, request):
# If cookie contains access token, put it inside authorization header
access_token = request.COOKIES.get('access_token')
if(access_token):
request.META['HTTP_AUTHORIZATION'] = '{header_type} {access_token}'.format(
header_type=settings.SIMPLE_JWT['AUTH_HEADER_TYPES'][0], access_token=access_token)
return super().authenticate(request)
网址.py
from .views import MyTokenObtainPairView
urlpatterns = [
......
path('auth/', include('djoser.urls')),
# path('auth/', include('djoser.urls.jwt')),
path('auth/api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
]
设置.py
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
'http://127.0.0.1:8000'
)
完美运行(使用 Httponly 在 cookie 中设置令牌。):
react侧
登录.js
axios.defaults.withCredentials = true
const Login = () => {
const [ivalue, setValue] = useState({});
const { state, dispatch } = useContext(Authcontext);
.......
const loginClick = (e) => {
e.preventDefault();
setLoader(true);
axios.post('http://127.0.0.1:8000/auth/api/token/', {
username: ivalue.username,
password: ivalue.password,
})
.then((res) => {
setValue({ password: "" });
dispatch({
type: LOGIN_SUCCESS,
});
setLoader(false);
history.push("/my_profile");
})
.catch((err) => {
setLoader(false);
setOpen({ act: true, msg: "error" });
dispatch({
type: LOGIN_ERROR,
});
setError(err.response.data);
});
};
.........
};
我的配置文件
axios.defaults.withCredentials = true
const MyProfile = () => {
const history = useHistory();
const { state, dispatch } = useContext(Authcontext);
useEffect(() => {
const auth_check = () => {
axios.get('http://127.0.0.1:8000/auth/users/me/')
.then((res) => {
dispatch({
type: AFTER_LOGIN,
payload: res.data
});
})
.catch((err) => {
history.push('/login')
});
};
auth_check();
}, []);
}
.......