I havent really changed anything and added a View to update some user data. Then i wanted to test my View and Django says that the current user is not authenticated. I logged out and logged in multiple Times and also looked at the requests in Burp. To me every looks fine, it always sends the session_id and also login goes through without problems. I also get my User Object returned to the frontend on login.
When i then try the "edit" function for the User then i'm unauthenticated...
This is my login:
#action(methods=['post'], detail=False, url_path='sign-in', url_name='sign-in')
def login_user(self, request):
email = str(request.data.get('email'))
password = str(request.data.get('password'))
if email is None or password is None:
return _ERROR_INCOMPLETE_CREDENTIALS
# User authentication...
user = authenticate_user(email=email, password=password)
if user is None:
return _ERROR_BAD_CREDENTIALS
user_profile = UserProfile.objects.get(id=user.id)
serialized_user = UserProfileSerializer([user_profile], many=True).data
print(serialized_user)
res = login(request, user)
print(res)
return Response(serialized_user, status=status.HTTP_200_OK)
This is the custom authenticate_user Method:
def authenticate_user(email, password):
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
This is a view which fails due to unauthentication:
#action(methods=['get'], detail=False, url_name='current', url_path='current')
def get_current_user(self, request):
if not request.user.is_authenticated:
return Response({"detail": "You need to be logged in for this!"}, status=status.HTTP_401_UNAUTHORIZED)
user = request.user
user_profile = UserProfile.objects.get(id=user.id)
return Response(UserProfileSerializer([user_profile], many=True).data)
Related
I have a user update api that is supposed to update the user's details. I have used set_password() to encrypt the password and from my print statements, it seems to encrypt fine. However when I save the updated user, the password still saves as plain text. What am I missing here ?
print(user.password) gives me
pbkdf2_sha256$216000$26YKhuRQ4i4S$HnfbowEjappYtP7nbbMZJXcjLi13sWPpj1EqjEbUutI=
Yet when I return user it maintains the password as plain text.
class UserDetail(APIView):
def get_user(self, pk):
try:
return User.objects.get(pk=pk)
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def put(self, request, pk, format=None):
user = self.get_user(pk)
data = request.data
new_password = data["password"]
user.set_password(new_password)
user.save()
print(user.password)
serializers = UserSerializer(user, request.data)
if serializers.is_valid():
serializers.save()
return Response(serializers.data)
else:
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
The code works as is, I'm just hoping somebody can provide an explanation here.
I set up a custom backend for my app. Code below:
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model
class AuthenticationBackend(BaseBackend):
def authenticate(self, request, username=None, password=None, email=None):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=email)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
And here is the view:
def login_view(request):
form = LoginForm(request.POST or None)
if request.POST and form.is_valid():
user = form.login(request)
if user:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
print(request.user)
return redirect('tasks')
context = {
'form': form
}
return render(request, 'users/login/index.html', context)
Along with the form (Note much of the login functionality was abstracted to the form)
class LoginForm(forms.Form):
email = forms.CharField(max_length=255, required=True, widget=forms.TextInput(attrs={'class': 'form_input'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form_input'}), required=True)
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
user = authenticate(email=email, password=password)
if not user or not user.is_active:
raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
return self.cleaned_data
def login(self, request):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
user = authenticate(email=email, password=password)
return user
In the login_view code, I had an issue. Before adding the "user.backend = ..." line, the system would login the user successfully, however upon redirecting to the 'tasks' view, the user would go back to Anonyomous.
After specifying the backend for the user prior to login, the code works fine.
Why do I need to specify the backend for the user prior to login? Is this because I'm using a custom backend? Did I mess up on the code somewhere?
Thank you in advanced!
Actually when you create more than one backend in the Django and register that backend in the Django settings Django is not able to identify for which backend this login functionality is so for that we have to specify the backend at login time or the other way is you can delete the default Django login backend but, if you delete that after that Django admin login might not work.
I have a custom login authentication with mysql table, while logging in how can I compare a hashed password with a plain-password in backends.py (Working fine with plain password)?
class MyBackEnd(object):
def authenticate(self, request, email=None, password=None):
existing_user = RegAuth.objects.get(email=email,password=password)
if not existing_user:
# Checking the user Regauth Custom DB.
user_data = RegAuth.objects.get(email=email,password=password)
if email == user_data.email:
user = RegAuth.objects.create_user(email=email, password=password)
user.save()
return user
else:
return None
else:
return existing_user
def get_user(self, email):
try:
return RegAuth.objects.get(email=email)
except Exception as e:
return False
Login view
def logauth(request):
if request.method == "POST":
email = request.POST['username']
password = request.POST['password']
user = authenticate(request, email=email, password=password)
if user is not None:
messages.error(request, 'if part : user is not None')
login(request, user)
return redirect('emp')
else:
messages.error(request, 'else part : user is None')
return redirect('login_url')
else:
messages.error(request, 'Please provide valid credentials')
return render(request, 'registration/login.html')
Is there any particular reason to diverge from Django's default authentication backend? I see at least a few issues with your authenticate method;
class MyBackEnd(object):
def authenticate(self, request, email=None, password=None):
# 1. password should not be used to retrieve a user, a pk should suffice
existing_user = RegAuth.objects.get(email=email,password=password)
if not existing_user:
# Checking the user Regauth Custom DB.
# 2. if the query before didn't yield results, why would it atp?
user_data = RegAuth.objects.get(email=email,password=password)
if email == user_data.email:
# 3. I'm not sure what flow validates this path, could you explain?
user = RegAuth.objects.create_user(email=email, password=password)
user.save()
return user
else:
return None
else:
return existing_user
For reference here's Django's default authenticate backend method (notice the use of except/else syntax):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
It;
Tries to retrieve the user, then;
Checks the password, and;
Validates the user's state, then;
Returns the user object to the caller (successful authentication), or
Does NOT return a user to the caller. (failed authentication)
Alternately (no user found), it;
Instantiates a user object, and;
Sets the password using set_password (which hashes it), then;
Does NOT return a user to the caller. (failed authentication)
This alternate flow's usage of set_password is meant to mitigate some timing attacks see: https://code.djangoproject.com/ticket/20760
If you want to register new users, reset a user's password, or anything besides authentication, the authenticate method is not the right place.
I am aware this is not an answer to your question, but I hope it helps you and possibly others to understand the authentication flow and be critical about diverging from it.
I'm Prety new in Django. After a few google search, I find full CRUD and I know how to handle that. But in User registration, I fell some problem all over the online every one uses Form.py to handle registration form but I don't want to use Form.py I like to customize it.
but the problem is when I use auth for login then Django auth says it's a wrong password
I use
authenticate(email=email,password=password)
for login check
Is anyone please explain custom login registration without using Form.py with some example.
Here is my View.py Code
def loginCheck(request):
if request.method == 'POST':
username = request.POST.get('username'),
password = request.POST.get('password'),
user = authenticate(request, username=username, password=password)
if user is not None:
return HttpResponse('Find User')
else:
return HttpResponse("Not Find User")
and my User Registration Code
def registration(request):
checkData = AuthUser.objects.filter(email=request.POST.get('email'))
if not checkData:
User.objects.create_user(
username=request.POST.get('username'),
email=request.POST.get('email'),
password=(request.POST.get('password')),
)
messages.add_message(request, messages.INFO, 'User Saved Successfully')
return redirect('loginView')
else:
messages.add_message(request, messages.INFO, 'Email Already Exists')
return redirect('loginView')
My Login code return Not Find User.
Try this minimal example. In this, you can create User and log in through API.
import json
from django.views.generic import View
from django.contrib.auth.models import User
from django.http import JsonResponse
from django.contrib.auth import authenticate, login
class UserRegisterView(View):
def get(self, request):
return JsonResponse({"message": "METHOD NOT ALLOWED"})
def post(self, request, *args, **kwargs):
json_body = json.loads(request.body)
username = json_body.get('username')
password = json_body.get('password')
email = json_body.get('email')
is_staff = json_body.get('is_staff', False)
is_superuser = json_body.get('is_superuser', False)
User.objects.create_user(
username=username, email=email,
password=password, is_staff=is_staff,
is_superuser=is_superuser
)
return JsonResponse({"message": "User created"})
class LoginView(View):
def get(self, request):
return JsonResponse({"message": "METHOD NOT ALLOWED"})
def post(self, request, *args, **kwargs):
'''
input data format:
{
"username" : "my username",
"password":"mysecret123#"
}
'''
json_body = json.loads(request.body)
username = json_body.get('username')
password = json_body.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return JsonResponse({"message": "login success"})
else:
return JsonResponse({"message": "login failed"})
Why I parsed request.body ?
How to receive json data using HTTP POST request in DJANGO
Reference:
How to authenticate user in DJANGO (official-doc)
UPDAYE-1
updated view as per the request,checking sufficent data in POST method (bold code)
def loginCheck(request):
if request.method == 'POST' and 'username' in request.POST and 'password' in request.POST:
username = request.POST.get('username'),
password = request.POST.get('password'),
user = authenticate(request, username=username, password=password)
if user is not None:
return HttpResponse('Find User')
else:
return HttpResponse("Not Find User")
return HttpResponse("POST data wrong")
If you want to your own registration process, you must use set_password function for saving password.
from django.contrib.auth.models import User
user = User.objects.get_or_create(username='john')
user.set_password('new password')
user.save()
I have a custom user model. After doing successful login, I am getting the anonymous user in HttpResponseRedirect and templates as well. How do I get the logged in user?
Login View:
class LoginFormView(View):
form_class = UserLoginForm
user_model = get_user_model()
template_name = 'account/login.html'
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('home'))
else:
messages.error(request, 'Please enter correct email and password!')
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
If you have the request template context processor enabled, you'll be able to access the user in the template with {{ request.user}}.
Secondly, make sure you are importing the login function and not the login view. It should be:
from django.contrib.auth import login