I'm using dj_rest_auth to authenticate my users and there is a problem with registration. After I create a user with RegisterView that dj_rest_auth gives, django creates the user without a problem but password hashing is incorrect and thus I can not login with new created user.
This is my Register View:
registerview.py
class UserRegisterAPIView(RegisterView):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# user.set_password(make_password(request.data.get('password'))) Didn't work
user = self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(self.get_response_data(user),
status=status.HTTP_201_CREATED,
headers=headers)
def perform_create(self, serializer):
user = serializer.save(self.request)
create_token(self.token_model, user, serializer)
complete_signup(self.request._request, user,
allauth_settings.EMAIL_VERIFICATION,
None)
return user
EDIT: These are the same password but hashed differently(First one is dj_rest_auth's register view, second one is created in admin panel)
If I use the second password on other users, they successfully log in.
I think you have a typo in your create method.
Where you have the commented section:
user.set_password(make_password(request.data.get('password')))
It should actually be:
user.set_password(make_password(serializer.data.get('password')))
I'm not sure what the function make_password does there, but that should solve the problem.
Related
I am begginer in Djnago and logged in to my app with this code:
class LoginHandler(TemplateView):
def get(self, request, *args, **kwargs):
user = authenticate(request, email='jaxen#gmail.com', password='123456')
login(request, user)
return render(request, "login.html", context={})
But i need to detect logged in user in other app that use DRF.
I don't know how fetch the user.
I tried this code but not worked:
class OtherAppHandler(APIView):
def post(self, request):
print(f"user: {request.user}")
...
Thank you.
I think that api is stateless. In api, you need to pass the authorization token from the front end to call API and then get the user from the request.user inside api.
I think you need to fetch the user. Using get method.
def get(self, request):
user_data = request.GET.get('user', '')
I am new to DRF and for learning I am writing test for my DRF Rest API. I am trying to test Login view, however, the test is failing even though I am providing correct credentials. Unusual thing is that it works perfectly fine when I am making a login request from Postman
I tried analyzing the data I provide, however I don't find any issues. In the test case I create new User and then try to log in.
My Test case:
def test_login_user(self):
"""
Ensure user can log in
"""
username = 'TestUserLogin'
password = 'test978453442'
url = reverse('login-list')
user = User.objects.create(
email='testUserLogin#test.com',
first_name='Matheus',
last_name='Smith',
password=password,
title='professor',
username=username,
groups=Group.objects.get(name=GROUPS[0])
)
response = self.client.post(url, {'username': username, 'password': password}, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
My Token Generator class
class CustomExpiringObtainAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
"""
Override!
Create token everytime this endpoint is called
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
if hasattr(user, 'auth_token'):
user.auth_token.delete()
token = Token.objects.create(user=user)
return Response({'token': token.key})
My Login View:
class LoginView(ViewSet):
serializer_class = AuthTokenSerializer
def create(self, request):
return CustomExpiringObtainAuthToken().as_view()(request=request._request)
Currently I've been using the generic login/register links (.../account/login, .../account/register etc) which lets all users (staff and non-staff) to login. I'm creating a separate app for only staff members and I'd like to have a separate endpoint link (.../acccount/staff-login) that would only allow staff members to get tokens. This seems pretty basic but I haven't been able to find anything for this.
Edit: MY SOLUTION : I simply reused the existing ObtainAuthToken view, and added a simple check for is_staff, if the user isn't staff I send an error status.
class StaffAuthToken(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
if coreapi_schema.is_enabled():
schema = ManualSchema(
fields=[
coreapi.Field(
name="username",
required=True,
location='form',
schema=coreschema.String(
title="Username",
description="Valid username for authentication",
),
),
coreapi.Field(
name="password",
required=True,
location='form',
schema=coreschema.String(
title="Password",
description="Valid password for authentication",
),
),
],
encoding="application/json",
)
def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def get_serializer(self, *args, **kwargs):
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
if (not user.is_staff): ## this is what I added
return Response(status = status.HTTP_403_FORBIDDEN)
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
You can do this using two different link...
1.link_for_non-staf
2.link_for_staf
Now listen that request in two different function in views.py.
def link_for_staff(request):
if request.method=="POST":
staff_form=AuthenticationForm(request,data=request.POST)
if form.is_valid():
username=staff_form.cleaned_data.get('username')
passowrd=staff_form.cleaned_data.get('password')
user=authenticate(username=username,passowrd=password)
if user is not None:
login(request,user)
return redirect('home')
Similarly you can create a another function to listen non-staff login request.
In your staff link no any other can login.
Don't forgot to import all import modules and variable names may be differ according to your choice.
What you have to do is create another authentication and check the user that's trying to login.
you can simply use IF statement.
`
if User.object.filter(fieldname=value, is_staff=True).exists():
do the auth......
else:
return the user back with error messeage
`
This will allow only the staff on the staff app. there are many ways to do this but this is the simplest.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I want to send password reset link to only confirmed email address. And also user can request password reset link by searching by username or email address which is not available in default django. I have been trying and editing the default django password reset view and form for many days. But not working for me.
you can extend PasswordResetView from
rest_auth.views
and do more logic in it
as in example
from rest_auth.views import PasswordChangeView, PasswordResetView, PasswordResetConfirmView
sensitive_post_parameters_m = method_decorator(
sensitive_post_parameters(
'password', 'old_password', 'new_password1', 'new_password2'
)
)
class PasswordResetViewNew(PasswordResetView):
def post(self, request, *args, **kwargs):
email = request.data.get('email')
try:
if User.objects.get(email=email).active:
return super(PasswordResetViewNew, self).post(request, *args, **kwargs)
except:
# this for if the email is not in the db of the system
return super(PasswordResetViewNew, self).post(request, *args, **kwargs)
in urls
path('password/reset/', PasswordResetViewNew.as_view()),
Edit to answer "How to search by username for sending password reset link"
the default serializer for the PasswordResetView contains
email = serializers.EmailField()
this mean the end point will not accept any thing except email
so we will do some tricks to make it accept chars so we can send user name to it
firstly we would extend
PasswordResetSerializer from rest_auth.serializers
and do some maintains
from rest_auth.serializers import PasswordResetSerializer
from django.conf import settings
from django.contrib.auth.forms import PasswordResetForm
class TestSerializer(PasswordResetSerializer):
email = serializers.CharField()
# here changed the email to accept any chars
reset_form = PasswordResetForm()
def validate_email(self, value):
#here we will trick it be make email really have the email of the username entered
mutable = self.initial_data
self.initial_data._mutable = True
self.initial_data['email'] = User.objects.get(username=self.initial_data.get('email'))
# don't forget to handle exception for username that not in db
self.initial_data._mutable = mutable
return super(TestSerializer, self).validate_email(value)
and with a little bit changes in our view like this
from django.utils.translation import gettext_lazy as _
#don't forget to import PasswordResetView, TestSerializer
class PasswordResetViewNew(PasswordResetView):
serializer_class = TestSerializer
# here we changed the default serializer to our new serializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.data['email'] = User.objects.get(username=serializer.data.get('email'))
# here we trick it again and change the email with the email for the username entered
serializer.save()
# Return the success message with OK HTTP status
return Response(
{"detail": _("Password reset e-mail has been sent.")},
status=status.HTTP_200_OK
)
sorry for my english. It is not good.
I work with rest framework django. I want to recover a user with his token. This Token must be sent via a post request
class GetUser(generics.ListCreateAPIView):
serializer_class = serializers.UserBasicSerializer
def get_queryset(self):
return models.Member.objects.filter()
def post(self, request, *args, **kwargs):
user = Token.objects.get(*args, **kwargs).user
i receive this error message
rest_framework.authtoken.models.MultipleObjectsReturned: get() returned more than one Token -- it returned 2!
thanks
Use:
user = Token.objects.filter(*args, **kwargs)
if user.exists():
user = user.last().user
The answer to your question is in the docs. Take a look here: http://www.django-rest-framework.org/api-guide/requests/#user
Basically, you just need to get from request the method user. For example:
def api_name_of_api(request):
user_data = request.user # Get username
user_data = request.user.id # Get user id
...