right now I have an api view that requires knowing which user is currently logged in. When I try to call it with a logged in user; however, it returns anonymous user. The odd thing is that if I call the api view again, it returns the proper user. I am using django rest framework and JSON Web Tokens with simplejwt. Right now the call in ReactJS looks like this:
const fetchAuthorData = () => {
axiosInstance.get('authors/')
.then((res) => {
setAuthor(res.data)
}).catch((err) => {
fetchAuthorData()
})
fetchAuthorThreads()
fetchAuthorArticles()
}
However, I know recursively calling this over and over is very dangerous, because even though I redirect if the user is actually not logged in before this recursive api call, if somehow that fails my server will be overloaded with api calls. Does anyone know how I could make it so that my api actually properly identifies on the first call whether the user is logged in?
Here is my login view:
axiosInstance.post('author-auth/token/', {
email: formData.email,
password: formData.password,
}).then((response) => {
localStorage.setItem('access_token', response.data.access)
localStorage.setItem('refresh_token', response.data.refresh)
axiosInstance.defaults.headers['Authorization'] =
'JWT ' localStorage.getItem('access_token')
history.push('/')
}).catch((err) => {
alert("Make Sure Login Credentials Are Correct")
})
Here is the faulty view:
@api_view(['GET'])
def author(request):
print(request.user)
if request.user.is_authenticated:
author = request.user
serializer = AuthorAccessSerializer(author, many=False)
return Response(serializer.data)
else:
return HttpResponse(status=400)
In this, request.user is an anonymous user even though I am logged in
Here is a similar part of another view that works oddly
@api_view(['GET', 'POST'])
def articles(request):
if request.method == 'GET':
category_name = request.query_params['category']
dash = request.query_params['dash']
#this part is very similiar and works for some reason
if dash == "True":
if request.user.is_authenticated:
articles = Article.objects.filter(author=request.user)
else:
return HttpResponse(status=401)
# *end part*
elif category_name:
try:
category = Category.objects.get(name__icontains=category_name)
except:
return HttpResponse(status=400, content="Category not found")
articles = Article.objects.filter(category=category)
else:
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
Here are my axios settings:
export const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers : {
Authorization: localStorage.getItem('access_token')
? 'JWT' localStorage.getItem('access_token')
: null,
'Content-Type' : 'application/json',
accept : 'application/json'
}
})
And here are my rest framework and JWT auth settings:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny'
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(hours=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer', 'JWT'),
'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',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
ALLOWED_HOSTS=['127.0.0.1', 'http://localhost:5000']
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
)
Again, if I keep calling the same api call, it works for some reason not changing any authorization headers, tokens, or anything else and request.user works fine with the second view I have above. Can anyone tell me why this is happening?
CodePudding user response:
I think,
1. localStorage.setItem('access_token', response.data.access)
2. localStorage.setItem('refresh_token', response.data.refresh)
3. axiosInstance.defaults.headers['Authorization'] =
'JWT ' localStorage.getItem('access_token')
history.push('/')
on login code may cause problem.
These code never run sequentially; every javascript run asynchronously.
It means, your axiosInstance.defaults.headers
could be null because, 1, 2 and 3 lines are executed at once. In other words, axiosInstance.defaults.headers
become null (as there is no access_token on localStorage) then, Js set access_token from response.data.access
.
You'd better use promise with .then()
after 1 and 2 line,
or fetch Authorization of axiosInstance when make http request.