I am trying to build an app which has user login and signup functionality.I can create login and signup both from django, and DRF but could not hook in oAuth2 with DRF to make it functional.I have no idea where should i use it.Should I generate token on signup or login?How can I make it functional?
Here is my code
serializers.py
class UserSerializer(ModelSerializer):
class Meta:
model = User
class UserCreateSerializer(ModelSerializer):
email = EmailField()
username = CharField()
first_name = CharField(required=False)
last_name = CharField(required=False)
password = CharField()
confirm_password = CharField()
class Meta:
model = User
fields = [
'username',
'email',
'first_name',
'last_name',
'password',
'confirm_password'
]
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
username = validated_data['username']
first_name = validated_data['first_name']
last_name = validated_data['last_name']
email = validated_data['email']
password = validated_data['password']
confirm_password = validated_data['password']
user_obj = User(
username = username,
first_name = first_name,
last_name = last_name,
email = email
)
user_obj.set_password(password)
user_obj.save()
return validated_data
class UserLoginSerializer(ModelSerializer):
username = CharField()
class Meta:
model = User
fields = [
'username',
# 'email',
'password',
# 'token',
]
extra_kwargs = {"password":
{"write_only": True}
}
def validate(self, data):
return data
views.py
class UserCreateAPI(CreateAPIView):
serializer_class = UserCreateSerializer
queryset = User.objects.all()
permission_classes = [AllowAny]
class UserLoginAPI(APIView):
permission_classes = [AllowAny]
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
data = request.data
print('data',data)
serializer = UserLoginSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
if new_data:
try:
user = User.objects.get(username=data['username'])
print ('user',user)
except ObjectDoesNotExist:
return HttpResponse("Can't find this user")
login(request, user)
return Response(new_data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
tools.py
def get_token_json(access_token):
return JsonResponse({
'access_token':access_token.token,
'expires_in':datetime.now() + timedelta(days=365),
'token_type':'Bearer',
'refresh_token':access_token.refresh_token.token,
'scope':access_token.scope
})
def get_access_token(user):
application = Application.objects.get(name="Foodie")
try:
old_access_token = AccessToken.objects.get(user=user, application=application)
old_refresh_token = RefreshToken.objects.get(user=user, access_token=old_access_token)
except ObjectDoesNotExist:
return HttpResponse('Have not set any token')
else:
old_access_token.delete()
old_refresh_token.delete()
new_token = generate_token()
refresh_token = generate_token()
access_token=AccessToken.objects.create(user=user, application=app, expires=datetime.now() + timedelta(days=365),token=new_token)
RefreshToken.objects.create(user=user, application=app, token=refresh_token, access_token=access_token)
print('aceess',AccessToken)
return get_token_json(access_token)
How can i bridge the gap between DRF and oAuth2 to make login and user registration functional?
Try using python social auth.
Add social.apps.django_app.default to INSTALLED_APPS
Add social.backends.facebook.FacebookOAuth2 to AUTHENTICATION_BACKENDS
Add url(r'^auth/', include('social.apps.django_app.urls', namespace='social')) to your urls.py
However this will work if you have session authentication in your app. If you want to use token based only, then either add a pipe to create the token and send it or take a look at https://github.com/PhilipGarnero/django-rest-framework-social-oauth2
Related
I have create my register endpoint with DRF, so far it has been working well but since I am trying it again it is sending error.
serializers.py
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True,max_length=68,min_length=8,error_messages=
{"min_length":f"Password must be longer than {MIN_LENGTH}characters"}, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True,max_length=68,min_length=8,error_messages={"min_length":f"Password must be longer than {MIN_LENGTH}characters"}, required=True)
class Meta:
model = User
fields = ('username','phone','password','password2')
extra_kwargs = {
'password': {'write_only': True},
'password2': {'write_only': True}
}
def validate(self,data):
if data["password"]!=data["password2"]:
raise serializers.ValidationError("password does not match!")
return data
def create(self,validated_data):
user = User.objects.create(
phone=self.validated_data['phone'],
username=self.validated_data['username'],
)
user.set_password(validated_data['password'])
user.save()
return user
views.py
class RegisterViewSet(viewsets.ModelViewSet):
http_method_names = ['post']
'''This endpoint is made to register all user with phone number and password'''
queryset = User.objects.all()
serializer_class = RegisterSerializer
I extended my user class to include other fields (city, country, bio). I would like to pass these down along to customizing my JWT access_token to include these fields as a payload in addition to username.
This is what I have in my models.py (extending my user class):
from django.db import models
from django.contrib.auth.models import User
#extending user model to include
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=50,blank=True)
country = models.CharField(max_length=50, blank=True)
bio = models.CharField(max_length=500, blank=True)
def __str__(self):
return self.user.username
serializers.py:
#changed from serializers.HyperLinked to ModelSerializer
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
#removed url from fields
fields = ['username', 'email', 'password', 'first_name', 'last_name', 'city', 'country', 'bio']
extra_kwargs = {
'password': {'write_only': True},
}
def create(self,validated_data):
user = Profile.objects.create_user(
username=validated_data['username'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
city=validated_data['city'],
country=validated_data['country'],
bio=validated_data['bio'],
email=validated_data['email'])
user.set_password(validated_data['password'])
user.save()
return user
#customizing the payload we get from our access tokens
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username
token['first_name'] = user.first_name
token['last_name'] = user.last_name
token['country'] = user.profile.country
token['city'] = user.profile.city
token['bio'] = user.profile.bio
return token
and api.py
#Register API
class RegisterApi(generics.GenericAPIView):
serializer_class = RegisterSerializer
#remove this if it doesn't work
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"message": "User Created Successfully. Now perform Login to get your token",
})
When I attempt to login now I get the error message:
AttributeError at /api/token/
'User' object has no attribute 'profile'
Request Method: POST
Request URL: http://127.0.0.1:8000/api/token/
I'm a beginner in Django and the rest framework and I'm trying to write a class-based login view with the rest framework for my register view please help me for writing a login class-based view what is important is view be class-based with rest
this is a registered view of my project and then its serializer at the bottom of that
class RegisterView(GenericAPIView):
serializer_class = UserSerializer
permission_classes = (permissions.AllowAny,)
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
user_data = serializer.data
user = User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
print(current_site)
# relativeLink = reverse('verify-email')
# print(type(relativeLink))
absurl = 'http://' + current_site + "?token=" + str(token)
email_body = 'سلام' + user.username + '\nبرای فعال سازی حساب خود وارد لینک زیر شوید' + '\n' \
+ absurl
data = {'email_body': email_body, 'to_email': user.email, 'email_subject': 'Verify your email'}
Util.send_email(data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
it is a register view serializer in serializer.py
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=65, min_length=8, write_only=True)
confirm_password = serializers.CharField(
max_length=65, min_length=8, write_only=True)
def validate_email(self, value):
lower_email = value.lower()
if User.objects.filter(email__iexact=lower_email).exists():
raise serializers.ValidationError("ایمیل تکراری است")
return lower_email
def validate(self, data):
if not data.get('password') or not data.get('confirm_password'):
raise serializers.ValidationError("لطفا پسورد را وارد و تایید کنید ")
if data.get('password') != data.get('confirm_password'):
raise serializers.ValidationError("پسورد اشتباه است")
return data
class Meta:
model = User
fields = ['username', 'email', 'password', 'confirm_password'
]
write_only_fields = ('password', 'repeat_password')
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
)
user.set_password(validated_data['password'])
user.set_password(validated_data['confirm_password'])
user.save()
return user
class LoginView(APIView):
def post(self, request):
username = request.data['username']
password = request.data['password']
# use a method to get access token (from the package you are using)
# access token class will return access token if the user is authenticated
# otherwise it will return error response
pass
After saving the user password field, the app shows an Invalid password format or unknown hashing algorithm.
User is created, but the password field is Invalid password format or unknown hashing algorithm.
The code does not return any error during registration.
I also tried user.set_unusable_password() in serializer but with the same result. Could not figure it out.
Serializers.py
from rest_framework import serializers
from accounts.models import User
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'phone' , 'password',)
write_only_fields = ('password',)
def create(self, validated_data):
user = User.objects.create(**validated_data)
user.set_password(validated_data['password'])
user.save()
return user
})
view.py
class Register(APIView):
def post(self, request, *args, **kwargs):
phone = request.data.get('phone', False)
password = request.data.get('password', False)
print(phone)
print(password)
if phone and password:
old = PhoneOTP.objects.filter(phone__iexact=phone)
if old.exists():
old = old.first()
validated = old.validate
if validated:
temp_data = {
'phone': phone,
'password': password
}
serializers = CreateUserSerializer(data=temp_data)
serializers.is_valid(raise_exception=True)
user = serializers.save()
old.delete()
return Response({
'status': True,
'detail': 'Account is created '
})
serializers.py
class UserRegistrationSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=False)
class Meta:
model = User
fields = ('phone', 'username', 'password', 'profile')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create_user(**validated_data)
users = Profile.objects.create(
user=user,
state=profile_data['state'],
city=profile_data['city'],
date_Of_Birth=profile_data['date_Of_Birth'],
address=profile_data['address']
)
users.save()
return users
views.py
class UserRegistrationView(CreateAPIView):
serializer_class = UserRegistrationSerializer
permission_classes = (IsAuthenticated,)
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
response = {
'success' : 'True',
'status code' : status.HTTP_200_OK,
'message': 'User registered successfully',
}
status_code = status.HTTP_200_OK
return Response(response, status=status_code)
Hope The answer is useful.
I am facing 2 issues here.
1) If user has not old token, a new one should be generated and logged in but it is not happening so.
2)A newly created user when logs in gets 'You have multiple authentication backends configured and therefore must provide the backend argument or set the backend attribute on the user.'
3)old user when trying to login gets an error of get() returned more than one AccessToken -- it returned 8!
Expert might understand from my code
class UserLoginAPI(APIView):
permission_classes = [AllowAny]
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
access_token = request.GET.get('access_token')
data = request.data
print('data',data)
serializer = UserLoginSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
if new_data:
app = Application.objects.get(name="Foodie")
try:
user = User.objects.get(username=data['username'])
print ('user',user)
except ObjectDoesNotExist:
return HttpResponse("Can't find this user")
else:
try:
access_token = AccessToken.objects.get(user=user)
except ObjectDoesNotExist:
return HttpResponse('Have not set any token')
else:
access_token.delete()
new_token = generate_token()
print('new_token',new_token)
AccessToken.objects.create(user=user, application=app, expires=datetime.now() + timedelta(days=365),token=new_token)
print('aceess',AccessToken)
login(request, user)
return Response(new_data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class UserLoginSerializer(ModelSerializer):
username = CharField()
class Meta:
model = User
fields = ['username', 'password']
class UserCreateSerializer(ModelSerializer):
class Meta:
model = User
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user_obj = User(
username = username,
first_name = first_name,
last_name = last_name,
email = email
)
user_obj.set_password(password)
user_obj.save()
if user_obj:
expire_seconds = oauth2_settings.user_settings['ACCESS_TOKEN_EXPIRE_SECONDS']
scopes = oauth2_settings.user_settings['SCOPES']
application = Application.objects.get(name="Foodie")
expires = datetime.now() + timedelta(seconds=expire_seconds)
access_token = AccessToken.objects.create(user=user_obj,
application=application,
token = generate_token(),
expires=expires,
scope=scopes)
return validated_data