Django jwt token error with react. «Данный токен не подходит ни для одного типа токенов, token_not_valid».
Я использую Django Rest Framework для аутентификации и Axios во фронтенде (reactjs).
Все работало нормально во время разработки, затем тестировалось на тестовом сервере в моей компании и jwt работал нормально, при развертывании на рабочем сервере я случайно получаю следующую ошибку :
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid",
"messages": [
{
"token_class": "AccessToken",
"token_type": "access",
"message": "Token is invalid or expired"
}
]
}
Иногда я получаю эту ошибку при первом вызове API после входа, в другой раз я получаю ее после отправки нескольких запросов после входа, также я никогда не получаю ее через postman
Я перечислю мой nginx conf и мой react config
nginx:
upstream api {
server ${DJANGO_API};
}
server {
listen 80 default_server;
server_name xx;
server_tokens off;
add_header X-Frame-Options "DENY";
proxy_cookie_flags one samesite=strict;
client_max_body_size 10M;
location /api/ {
proxy_pass http://api$request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /admin/ {
proxy_pass http://api$request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /swagger/ {
proxy_pass http://api$request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /redoc/ {
proxy_pass http://api$request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/app/web/staticfiles/;
expires 1y;
add_header 'Cache-Control' 'public, immutable';
}
# ignore cache frontend
location ~* (service-worker\.js)$ {
add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
expires off;
proxy_no_cache 1;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
expires 1y;
add_header 'Cache-Control' 'public, immutable';
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Обратите внимание, что xx - это ip тестового сервера, а не prod-сервера, повлияет ли это на что-нибудь?
reacjs:
const prod = {
REACT_APP_CURRENT_DOMAIN:"eKYC",
REACT_APP_CURRENT_VERSION:"1.2",
REACT_APP_CURRENT_HOST:`${window.location.origin}`,
};
const dev = {
REACT_APP_CURRENT_DOMAIN:"eKYC",
REACT_APP_CURRENT_VERSION:"1.0",
REACT_APP_CURRENT_HOST:"http://localhost:8000",
};
export const config = process.env.NODE_ENV === "development" ? dev : prod;
const setAuthToken = (token, permissions) => {
if (token) {
localStorage.setItem("token", token);
localStorage.setItem("permissions", JSON.stringify(permissions));
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
axios.defaults.headers.common["Accept"] = `application/json; version=${config.REACT_APP_CURRENT_VERSION}`;
} else {
localStorage.removeItem("token");
localStorage.removeItem("permissions");
delete axios.defaults.headers.common.Authorization;
delete axios.defaults.headers.common["Accept"];
}
};
export const login = (userData, setReloadModal) => {
return (dispatch, getState) => {
dispatch({
type: actionTypes.SET_CURRENT_USER_LOADING,
payload: true,
});
axios
.post(
`${config.REACT_APP_CURRENT_HOST}/api/login/`,
{
...userData,
entity: getState().auth.bank,
app_ver: `${config.REACT_APP_CURRENT_VERSION}`,
},
{
timeout: 120000,
headers: {
Accept: `application/json; version=${config.REACT_APP_CURRENT_VERSION}`,
},
}
)
.then((res) => res.data)
.then((user) => {
setAuthToken(user.access, user.permissions);
return dispatch({
type: actionTypes.SET_CURRENT_USER,
payload: {
user: { username: user.username, name: user.name },
bank: user.entity,
permissions: user.permissions,
loading: false,
authenticated: true,
unauthorized: "",
},
});
})
.catch((err) => {
transformErrorResponse(err);
if (err.response) {
if (!isUndefined(err.response.data.non_field_errors)) {
if (
err.response.data.non_field_errors[0] ===
"الرجاء اعادة تحميل الصفحة بالضغط على F5 + Ctrl"
) {
setReloadModal(true);
return dispatch({
type: actionTypes.SET_CURRENT_USER_LOADING,
payload: false,
});
}
}
return dispatch({
type: actionTypes.SET_CURRENT_USER_FAIL,
payload: {
errors: {
...getState().auth.errors,
...err.response.data,
},
loading: false,
},
});
} else {
return dispatch({
type: actionTypes.SET_CURRENT_USER_FAIL,
payload: {
errors: {
...getState().auth.errors,
non_field_errors: [" غير متصل بالشبكة"],
},
loading: false,
},
});
}
});
};
};
Настройки Django:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '20/min',
'user': '20/min'
},
'EXCEPTION_HANDLER': 'api.utils.custom_exception_handler',
'DATETIME_FORMAT': "%m/%d/%Y %H:%M:%S",
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning',
'DEFAULT_VERSION': APP_VER,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 15
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": datetime.timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": datetime.timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
"UPDATE_LAST_LOGIN": False,
"ALGORITHM": "HS256",
"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": datetime.timedelta(minutes=5),
"SLIDING_TOKEN_REFRESH_LIFETIME": datetime.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",
}
DEFENDER_LOGIN_FAILURE_LIMIT = 6
DEFENDER_REDIS_URL= get_secret("DEFENDER_REDIS_URL")
DEFENDER_COOLOFF_TIME = 900
DEFENDER_DISABLE_USERNAME_LOCKOUT = False
DEFENDER_DISABLE_IP_LOCKOUT = True
DEFENDER_BEHIND_REVERSE_PROXY = True
DEFENDER_REVERSE_PROXY_HEADER = "HTTP_X_FORWARDED_FOR"
мой докер-файл prod :
version: '3.8'
services:
web:
image: xxx:5000/ekyc_web:${VER}
restart: unless-stopped
build:
context: ./django_backend
dockerfile: Dockerfile.prod
command: sh -c "python manage.py collectstatic --no-input --clear &&
python manage.py makemigrations &&
python manage.py migrate &&
gunicorn --worker-class gevent --worker-connections 100 django_backend.wsgi:application --bind 0.0.0.0:8005"
volumes:
- static_volume:/home/app/web/staticfiles
ports:
- 8005
env_file:
- ./django_backend/.env.prod
depends_on:
- redis
secrets:
- eKYC_django_secrets
deploy:
replicas: 3
placement:
max_replicas_per_node: 3
restart_policy:
condition: on-failure
app-prod:
restart: unless-stopped
image: xxx:5000/ekyc_app-prod:${VER}
build:
context: ./react-frontend
dockerfile: Dockerfile.prod
command: >
/bin/sh -c
"envsubst '
$${DJANGO_API}
'< /etc/nginx/templates/default.conf.template
> /etc/nginx/conf.d/default.conf
&& nginx -g 'daemon off;'"
volumes:
- static_volume:/home/app/web/staticfiles
ports:
- '86:80'
environment:
- NODE_ENV=production
- DJANGO_API=web:8005
depends_on:
- web
deploy:
replicas: 3
placement:
max_replicas_per_node: 3
restart_policy:
condition: on-failure
redis:
image: xxx:5000/ekyc_redis:${VER}
build:
context: ./redis
dockerfile: Dockerfile
ports:
- "6383:6383"
- "4382:4382"
command: redis-server --port 6383 --appendonly yes
volumes:
- data:/home/docker/data
deploy:
replicas: 3
placement:
max_replicas_per_node: 3
restart_policy:
condition: on-failure
volumes:
static_volume:
data:
secrets:
eKYC_django_secrets:
file: ${LOC}/eKYC_django_secrets.json