Token generated by django-restframework-simplejwt not valid - django

This was working just fine before I tried to add social authentication to the project, and now when I send the verification email with the token, the token verifier says that the token is not valid!
class ResendVerifyEmail(APIView):
serializer_class = RegisterSerialzer
def post(self, request):
data = request.data
# email = data.get('email')
email = data['email']
print(email)
try:
user = User.objects.get(email=email)
# print('hello')
if user.is_verified:
return Response({'msg':'User is already verified','status':'status.HTTP_400_BAD_REQUEST'})
print (user.username)
token = RefreshToken.for_user(user).access_token
current_site= get_current_site(request).domain
relativeLink = reverse('email-verify')
absurl = 'http://'+current_site+relativeLink+"?token="+str(token)
email_body = 'Hi '+ user.username + ' this is the resent link to verify your email \n' + absurl
data = {'email_body':email_body,'to_email':user.email,
'email_subject':'Verify your email'}
Util.send_email(data)
return Response({'msg':'The verification email has been sent','status':'status.HTTP_201_CREATED'}, status=status.HTTP_201_CREATED)
except User.DoesNotExist:
return Response({'msg':'No such user, register first','status':'status.HTTP_400_BAD_REQUEST'})
class VerifyEmail(APIView):
serializer_class = EmailVerificationSerializer
def get(self, request):
token = request.GET.get('token')
try:
payload = jwt.decode(token, settings.SECRET_KEY)
# print('decoded')
user = User.objects.filter(id=payload['user_id']).first()
# print(user)
if user.is_verified:
return Response({'msg':'User already verified!'}, status=status.HTTP_400_BAD_REQUEST)
else:
user.is_verified = True
# user.is_authenticated = True
user.is_active = True
# if not user.is_verified:
user.save()
return Response({'email':'successfuly activated','status':'status.HTTP_200_OK'}, status=status.HTTP_200_OK)
# except jwt.ExpiredSignatureError as identifier:
except jwt.ExpiredSignatureError:
return Response({'error':'Activation Expired','status':'status.HTTP_400_BAD_REQUEST'}, status=status.HTTP_400_BAD_REQUEST)
# except jwt.exceptions.DecodeError as identifier:
except jwt.exceptions.DecodeError:
return Response({'error':'invalid token','status':'status.HTTP_400_BAD_REQUEST'}, status=status.HTTP_400_BAD_REQUEST)
also, I have added these in settings.py
AUTHENTICATION_BACKENDS = (
'social_core.backends.facebook.FacebookOAuth2',
'django.contrib.auth.backends.ModelBackend',
)
I get 'jwt.exceptions.DecodeError'

This did the job
payload = jwt.decode(token, settings.SECRET_KEY, algorithms='HS256')

Related

How can I decode a token sent to a user to know when it was created

Hello I did a reset password system in my web that sends a token link to the client's mail in order to client can reset the password, And I want to check the timestap of the hashed token, to make some condition like... expire in 24h.
This file makes the token and I "guess" is hashing user.pk and timestap and returning a hashed token. I want to make reverse process to know when that token was created.
tokens.py:
from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp)
)
account_activation_token = AccountActivationTokenGenerator()
Token link is going perfect and client can change the passord whitn no problems.
this is my view that handle this with 2 functions 1st for sending the mail, and 2nd for reset the password.
views.py:
def reset_password(request):
form = ResetPasswordForm(request.POST or None)
if form.is_valid():
user = User.objects.filter(email=form.cleaned_data.get('email'))
if not user:
messages.error(request,'This user does not exist')
else:
user = user.first()
current_site = get_current_site(request)
subject = 'Reset Password'
message = render_to_string('core/reset_password_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
send_mail(subject,message,conf_settings.EMAIL_HOST_USER,[user.email,])
messages.success(request,'Password reset link sent to your email')
return redirect('consumer:consumer_home')
context = {
'form':form,
}
return render(request,'core/password_reset.html',context)
def reset_password_confirm(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
form = ResetPasswordConfirmationForm(request.POST or None)
if form.is_valid():
password = form.cleaned_data.get('password1')
user.set_password(password)
user.save()
login(request,user)
messages.success(request,'Password changed!')
return redirect('consumer:consumer_home')
context = {
'form':form,
}
return render(request,'core/password_reset_confirmation.html',context)
Now I have no clue to how to decode client token in order to extract the timestap that I hashed when I sent it in the first place.
From what I gather, you can update your AccountActivationTokenGenerator to include a timestamp:
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(time.time())
)
You can then create a function to check the token when confirming the reset:
def reset_password_confirm(request, uidb64, token):
def check_token(token):
try:
user_id, timestamp, creation_time = token.split(":")
user = User.objects.get(pk=user_id)
if account_activation_token._make_hash_value(user, timestamp) != token:
return False
return user, creation_time
except Exception:
return False
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
result = check_token(token)
if user is not None and result:
user, creation_time = result
form = ResetPasswordConfirmationForm(request.POST or None)
if form.is_valid():
password = form.cleaned_data.get("password1")
user.set_password(password)
user.save()
login(request, user)
messages.success(request, "Password changed!")
return redirect("consumer:consumer_home")
context = {'form':form,}
return render(request, "core/password_reset_confirmation.html", context)
You'll then have access to creation_time which you can use in template through context.

'User' object has no attribute 'user', Where is the problem?

My goal is to reset the password via mail. But the profile_obj of the ChangePassword view returns None and 'NoneType' object has no attribute 'user'. Why? I tried different ways but did not work. The ForgetPassword view working well. The ChangePassword view doesn't work. Where is the problem? give me a relevant solution.
views.py:
def ForgetPassword(request):
try:
if request.method == 'POST':
email = request.POST.get('email')
if not User.objects.filter(email=email).first():
messages.warning(request, 'Not email found with this email.')
return redirect('ForgetPassword')
user_obj = User.objects.get(email = email)
token = str(uuid.uuid4())
send_forget_password_mail(user_obj.email , token)
messages.success(request, 'Please check your mail box an email is send.')
return redirect('ForgetPassword')
except Exception as e:
print(e)
context = {
}
return render(request, "forget_password_email.html", context)
def ChangePassword(request, token):
context = {}
try:
profile_obj = User.objects.filter(forget_password_token=token).first()
print(profile_obj)
if request.method == 'POST':
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('reconfirm_password')
user_id = request.POST.get('user_id')
if user_id is None:
messages.warning(request, 'No user id found.')
return redirect(f'/ChangePassword/{token}/')
if new_password != confirm_password:
messages.warning(request, 'both should be equal.')
return redirect(f'/ChangePassword/{token}/')
profile_obj.password = new_password
profile_obj.save()
user_obj = User.objects.get(id = user_id)
user_obj.set_password(new_password)
user_obj.save()
return redirect('Login')
context = {'user_id' : profile_obj.user.id}
except Exception as e:
print(e)
context = {
}
return render(request,'change_password.html', context)
helpers.py:
from django.core.mail import send_mail
from django.conf import settings
def send_forget_password_mail(email , token ):
subject = 'Your forget password link'
message = f'Hi , click on the link to reset your password http://127.0.0.1:8000/ChangePassword/{token}/'
email_from = settings.EMAIL_HOST_USER
recipient_list = [email]
send_mail(subject, message, email_from, recipient_list)
return True
models.py:
class User(AbstractUser):
email = models.EmailField(max_length=50, unique=True, error_messages={"unique":"The email must be unique!"})
REQUIRES_FIELDS = ["email"]
objects = CustomeUserManager()
forget_password_token = models.CharField(null= True, max_length=100, blank=True)
def __str__(self):
return f"{self.pk}.{self.email}"
urls.py:
path('ForgetPassword/', views.ForgetPassword, name="ForgetPassword"),
path('ChangePassword/<token>/', views.ChangePassword, name="ChangePassword")
Your context in the ChangePassword function is :
context = {'user_id' : profile_obj.user.id}
Your error here is that profile_obj is a QuerySet and you are looking for a user field in a queryset and not in a model instance(model) like user_obj.
Also, you can't change a password this way in a queryset:
profile_obj.password = new_password
profile_obj.save()
This works on model instances.
You need to rewrite your view to either get a User instance and then return it's id to your context or use the already created user_obj you are getting later in your code.
context = {'user_id' : user_obj.id}

How can I add uuid to url in urls.py django?

I have django app with authentication in it and email verification. When user is created activation email is sent with link inside of it, when user clicks this link is doesn't take him nowhere.
views.py
class customer_register(CreateView):
model = User
form_class = CustomerSignUpForm
template_name = 'authentication/customer_register.html'
def form_valid(self, form):
user = form.save()
user.token = str(uuid.uuid4())
subject = 'Verify your account | Zane'
message = f"http://127.0.0.1:8000/accounts/verify/{user.token}/"
recipient_list = [user.email]
send_mail(
subject,
message,
'from#example.com',
['to#example.com'],
fail_silently=False,
)
return redirect('/')
def activate(request, token):
try:
obj = models.User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', views.activate, name='activate'),
models.py
...
token = models.CharField(max_length=200, blank=True)
signup_confirmation = models.BooleanField(default=False)
I wonder what do I need to put in my url to trigger my function?
I would rewrite your active view as a class. Here is an example:
class ActivateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
token = kwargs['pk']
try:
obj = User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', ActivateView.as_view(), name='activate'),

How to make log-in with Django rest api

hello i learning about Django rest api, I am learning through someone else's code, but I don't know how to make Login.
my code :
model:
class User(models.Model):
class Meta:
db_table = "users"
created_at = models.DateTimeField(default = timezone.now)
updated_ay = models.DateTimeField(auto_now= True)
email = models.CharField(max_length = 128, unique= True)
password = models.CharField(max_length = 255)
active = models.BooleanField(default=False)
token = models.CharField(max_length= 255, null = True)
nickname = models.CharField(max_length = 255, null = True)
serializer:
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
class Meta:
model = User
fields = '__all__'
def to_internal_value(self, data):
ret = super(UserSerializer, self).to_internal_value(data)
# cipher = AESSipher()
# ret['password'] = cipher.encrypt_str(ret['password'])
return ret
def to_representation(self, obj):
ret = super(UserSerializer, self).to_representation(obj)
print(ret)
return ret
def validate_email(self, value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("Email already exists")
return value
def validate_password(self, value):
if len(value) < 8:
raise serializers.ValidationError("The password must be at least %s characters long. " % 8)
return value
def create(self, validate_data):
user = User.objects.create(
email = validate_data['email'],
password = validate_data['password'],
)
user.active = False
user.save()
message = render_to_string('user/account_activate_email.html', {
'user': user,
'domain' : 'localhost:8000',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user)
})
mail_subject = 'sign up mail.'
to_email = 'mymail#gmail.com'
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return validate_data
views:
class SignUp(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserActivate(APIView):
permission_classes = (permissions.AllowAny,)
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk = uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
try:
if user is not None and account_activation_token.check_token(user, token):
user.active = True
user.token = token
user.save()
return Response(user.email + 'email active', status=status.HTTP_200_OK)
else:
return Response('Expired Link', status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
print(traceback.format_exc())
Since I want to handle log-in status in the Mobile Client section,
I want to get only user model information when I log-in.
When Enter Email and Password in Client and I want to get user information.
How to make log-in? Do you know anyone?
Here is the link to the article: custom user authentication; it should help you
https://wsvincent.com/django-rest-framework-user-authentication-tutorial/
Hi you can use Django packages for this. for example you can use rest-auth package this package have all the things that you need for log in log out and reset password and all you need is that follow the rest auth documentation :
. https://pypi.org/project/django-rest-auth/
. https://django-rest-auth.readthedocs.io/en/latest/

django facebook and user password authentication

i am new in django, i require login with user and password or facebook, i am using rest framework for api endpoints. ¿How i can do it?
i try with:
django-rest-framework-social-oauth2 but don't work for my because i needs save additional info from user after first enter.
I expect have 2 endpoint one sending user and password and another sending facebook auth token
Here's sample code for user login for Django Rest Framework:
class Login(APIView):
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(Login, self).dispatch(*args, **kwargs)
#staticmethod
def post(request):
request_data = JSONParser().parse(request)
if 'email' in request_data and 'password' in request_data:
try:
validate_email(request_data['email'])
except ValidationError:
return JsonResponse({'result': 'E-mail is invalid'}, status=400)
user = authenticate(email=request_data['email'], password=request_data['password'])
if user is not None:
if user.is_active:
try:
token = Token.objects.get(user=user)
except Token.DoesNotExist:
token = Token.objects.create(user=user)
return JsonResponse({'result': 'success', 'token': token.key, 'id': user.id}, status=200)
return JsonResponse({'result': 'E-mail or password is incorrect'}, status=400)
return JsonResponse({'result': 'E-mail or password is empty'}, status=400)
Here's sample for FB login code for Django Rest Framework (from my test project):
class FbLogin(APIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.AllowAny,)
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(FbLogin, self).dispatch(*args, **kwargs)
#staticmethod
def post(request):
request_data = JSONParser().parse(request)
if 'access_token' in request_data:
response = requests.get(
url='https://graph.facebook.com/v2.5/me/',
params={
'access_token': request_data['access_token'],
'fields': 'email,first_name,last_name',
},
)
json_response = json.loads(response.text)
if 'error' not in json_response:
response_photo = requests.get(
url='https://graph.facebook.com/v2.5/%s/picture' % json_response['id'],
params={
'redirect': 'false',
'type': 'large',
},
)
response_photo_json = json.loads(response_photo.text)
response_friends = requests.get(
url='https://graph.facebook.com/v2.5/me/friends/',
params={
'access_token': request_data['access_token'],
'limit': 300,
},
)
generated_password = get_random_string(10, '0123456789abcdefghijklmnopqrstuvwxyz')
try:
json_response_email = json_response['email']
except:
first_name = json_response['first_name'].lower()
last_name = json_response['last_name'].lower()
id = json_response['id']
json_response_email = first_name + last_name + id + '#facebook.com'
try:
current_user = User.objects.get(email=json_response_email)
current_user.set_password(generated_password)
current_user.save()
except User.DoesNotExist:
new_user = User.objects.create_user(email=json_response_email,
password=generated_password)
new_user.provider_id = json_response['id']
new_user.provider_type = 'facebook'
if 'first_name' in json_response:
new_user.first_name = json_response['first_name']
if 'last_name' in json_response:
new_user.last_name = json_response['last_name']
new_user.save()
photo_name = urlparse(response_photo_json['data']['url']).path.split('/')[-1].split('?')[-1]
photo_content = urllib.request.urlretrieve(response_photo_json['data']['url'])
new_user.profile_photo.save(photo_name, File(open(photo_content[0], 'rb')), save=True)
user = authenticate(email=json_response_email, password=generated_password)
try:
token = Token.objects.get(user=user)
except Token.DoesNotExist:
token = Token.objects.create(user=user)
if user is not None:
if user.is_active:
fullname = json_response['first_name'] + ' ' + json_response['last_name']
return JsonResponse({'result': 'success', 'token': token.key, 'name': fullname}, status=200)
return JsonResponse({'result': 'User access token is incorrect'}, status=400)