Django-registration setup without password - django

I am trying to make a website, where people only put their email addresses and they are logged in with cookies and all. At a later stage, i will ask them provide password and names, but NO username will be used. I am trying to do this with django-registraition, but i get errors and i have a few problems.
First to disable usernames as a login feature, i put str(time()) instead of username - i was looking for something that will change every time.
However, when I skip the authentication (which i currently don't need) i get error:
'RegistrationProfile' object has no attribute 'backend'
Alternatively, i can leave the authentication but then i don't know how to authenticate it only with email and no password. Also, i don't know how to make the next line work:
auth.login(request, ProfileUser)
If anyone can get me out of here, it would be awesome. Here is some code:
my form Class:
class RegistrationFormCustom(forms.Form):
email = forms.EmailField()
def do_save(self):
new_u = User(username=str(time()),email= self.cleaned_data.get('email'),)
new_u.save()
new_p = Profile.objects.create_profile(new_u)
new_p.save()
return new_p
my view:
def registerCustom(request, backend, success_url=None, form_class=None,
disallowed_url='registration_disallowed',
template_name='registration/registration_form.html',
extra_context=None,
initial={}):
form = RegistrationFormCustom(initial=initial)
if request.method == 'POST':
form = RegistrationFormCustom(initial=initial, data=request.POST)
if form.is_valid():
profile = form.do_save()
profile = auth.authenticate(username = profile.user.email, password = form.cleaned_data.get('pass1'))
print(profile)
auth.login(request, profile)
return redirect('/')
else:
pass
return render_jinja(request, 'registration/registration_form.html',
type="register",
form = form
)
and i will post any other snipped required happily

You're getting the 'RegistrationProfile' object has no attribute 'backend' error because the user is not yet authenticated. To log someone in, you have to call the authenticate method first, which requires a password. So, what you can do instead, is this:
from django.contrib.auth import load_backend, login, logout
from django.conf import settings
def _login_user(request, user):
"""
Log in a user without requiring credentials (using ``login`` from
``django.contrib.auth``, first finding a matching backend).
"""
if not hasattr(user, 'backend'):
for backend in settings.AUTHENTICATION_BACKENDS:
if user == load_backend(backend).get_user(user.pk):
user.backend = backend
break
if hasattr(user, 'backend'):
return login(request, user)
Then, to log someone in, just call the _login_user function with the request and User model. (This will be profile.user in your case, probably) Do this instead of calling auth.login. I'm not sure on how you're going to determine whether this is a valid user or not, without a password or username, but I'll leave that to you. If you still have trouble, let me know.
Short Explanation:
What basically happens here is that Django requires a user to be authenticated in order to be logged in via the login function. That authentication is usually done by the authenticate function, which requires a username and password, and checks whether the supplied password matches the hashed version in the database. If it does, it adds an authentication backend to the User model.
So, since you don't have a password and username, you just have to write your own method for adding the authentication backend to the User model. And that's what my _login_user) function does - if the user is already authenticated, it just calls login, otherwise, it first adds the default backend to the User model, without checking for a correct username and password (like authenticate does).

For others reading this thread, I got a similar error message when I was using User.objects.create() instead of User.objects.create_user(). Basically, the first method was setting a clear password whereas create_user encrypts the password. Clear passwords will fail to authenticate. Check your database, if you have passwords set in the clear, then it's likely you need to use create_user() instead.
The author's request could be fixed by simply setting a default user and password using create_user() instead of just user.save().

You can create a known password (put it in settings.py ) and use that as though the user entered it. Create the user with this and authenticate the user with this.

Related

In Django what does the request argument in a method do?

I have seen a few codes where sometimes the authenticate method have the request argument while other times it does not, e.g. see the below codes:
Code 1:
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
# code for automatic login after singing up
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
Code 2:
def login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
According to the official docs:
request is an HttpRequest and maybe None if it wasn’t provided to
authenticate() (which passes it on to the backend).
What does this request argument actually do and when should I consider passing it in the authenticate method?
According to the Django docs, and confirmed by me just now looking at the source, this is passed to the authenticate method of whatever authentication backend you are using.
The only backend class that seems to use it is the RemoteUserBackend, and the reason for this is because RemoteUserBackend will create a local User model instance the first time a user (who already exists in the remote auth database) logs in, and then, before returning the user instance, the backend calls its own configure_user method, passing the new user instance, along with request.
Docs for that here: https://docs.djangoproject.com/en/3.1/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend
But, here's where it gets silly.. is that, the default implementation of configure_user doesn't actually do anything, it's just a stub that you can extend in a subclass of RemoteUserBackend that you may choose to write if you want to add your own behavior to it.
Clear as mud. But really it makes sense. Perhaps some parameters were passed in the request that triggered the need for authentication, and some of those parameters contain information about the user that needs be stored in the newly created User instance... The request object contains everything known about the request, it comes in handy.
Suffice to say that somebody, some time, either wrote an auth backend that required access to the request at this point, or the author of the auth module anticipated that someone might need it some day. But in the auth module itself, by default, request is not used for anything that I can see.
So it doesn't seem necessary to pass request to authenticate, but if you can imagine that in the future you might want to configure your application with a funky authentication backend, you might want to pass it.. just in case it's needed by that backend. The default ModelBackend doesn't use it.
The context for your question is that django is a web server. In the classic HTTP/1 world, django receives a request and returns a response. The request argument typically represents the http request that is sent from the user's browser to the server to which django will be responding.
So, in the first function in your code, register appears to be intended to be used as part of a view to register a new user. The request, in this case, is useful to allow the register function to access the values that were entered in by the user in registering that user with the website. The same goes for login. The only specific reason that these function accept a request is that it allows the function to evaluate and take some action with respect to the information that the user submitted in the request.

login/check the username and password from database in Django website using post request

I have created a blog website where I want to login a user whose username and password are saved in a database table, named "myuser". I have already fetched the username and password from post request in my function.
Now how can I compare this value from my already created table values to check whether the username and password are correct or not?
You can't manually check the password. Because when you are creating a user, django is storing the user's password as a hash value in the database. Now if you are storing the raw password in your custom table which is myuser, it's not a good practice.
Because if someone gets access in your database, he can see the tables too. And what he will find? The precious, delicious passwords of all the users.
If you are storing the raw password i.e. mypassword12345 he just got the actual password. If you use the default django method, django will store the password like this: jkashdu12321kandsxn!312nasdkhj, for example, which is the hash for your mypassword12345. And now the attacker will see the password as jkashdu12321kandsxn!312nasdkhj this which is a hash value of your password. Django uses some strong hashing algorithm, therefore, the attacker can't easily crack your password.
So even if he gets the access of your database, he won't be able to do much except deleting documents. (which is severe but you'll be storing the backup, right?)
So if you are storing the password raw, please don't. It's for your application security.
And now, when you just got the username and password in your function which is given by your user and you want to check if the user exists or not, you can follow what #MalikFaiq suggested which is:
from django.contrib.auth.models import User
check_if_user_exists = User.objects.filter(yourtablefield="yourusername").exists()
Now if check_if_user_exists is true, it means there's a user with this username in your table. If it's false then there is no user.
Now what you'll be wanting is to check if this user is giving you the right password. You can check by doing the following:
if check_if_user_exists:
user = authenticate(request, username=username, password=password)
if user is not None:
# this user is valid, do what you want to do
else:
# this user is not valid, he provided wrong password, show some error message
else:
# there is no such entry with this username in the table
Hope it helps.
You can check user by importing model from your model class.
from django.contrib.auth.models import User
bool_answer = User.objects.filter(yourtablefield="yourusername").exists()
if bool_answer is True then it means user exists other wise not.
You need to check whether the user exists or not in your "myusertable", if yes, whether the password matches or not.
If active, exists and password matches, use the django sessions framework [most convenient] or the django cache/cookie framework to log in the user and store a session that the user is logged in.
def loginView(request):
# after checking if the user is active, exists and passwword matches
request.session["isLoggedIn"] = True
request.session["username"] = request.POST.get("username")
In your templates
Note: Make sure "django.core.context_processors.request" is in your context processors in settings.py
{% if request.session.isLoggedIn %}
{{request.session.username}}
{% else if not request.session.isLoggedIn %}
<p>User not in session or logged off</p>
{% endif %
You shouldn't store usernames/passwords on your own.
from django.http import HttpResponseForbidden
from django.contrib.auth import authenticate
# Authenticate
user = authenticate(username=username, password=password)
if user is None:
return HttpResponseForbidden()
else:
# Ready for operation
...
First, you get the email &password from the form then use table name to get all table then chose the email and password from table
if (request.method == 'GET'):
return render(request, 'login.html')
else:
email = request.POST['email']
password = request.POST['password']
intakes = Intake.objects.all().filter(email=email,password=password)
for intake in intakes:
if intake.email==email and intake.password==password:
return render(request, "nav.html")
else:
return render(request, "signup.html")

how to generate token using username and pin field in django auth toolkit for a phone app while keeping username and password for the web application?

I am using DRF with auth toolkit and it is working fine. However, I want to have a second login api so a user can log in using username and pin number. It is cos we have a USSD application and it is easier to give them a pin based login system.
Currently, I have the following URL that, when called, generates token:
url(r'^signin/', include('oauth2_provider.urls', namespace='oauth2_provider')),
For the ussd app, I want something like that but the auth2 should check pin field, defined in a separate model defined as follows:
class Members(models.Model):
pin=models.IntegerField()
user=models.ForeignKey(User)
I am a little lost where to start.
Using this answer as a base to answer this question, and Django's documentation.
I would say you'd want to create a custom authentication backend, and you'd want a custom user model with two passwords, or using a one-to-one relationship to add the additional password field, something like so:
from django.contrib.auth.models import AbstractBaseUser
class UserExtension(AbstractBaseUser):
user = models.OneToOneField(User)
...
Inheriting from the AbstractBaseUser should add a password field like the user model, (although I haven't tried this). If you prefer the custom user approach, I actually have a github repo that has a custom user app, so if you'd like to get any ideas of how to achieve this check it out.
Or have a look through the documentation.
Either way, once you've got your two passwords, you need to decide which one to use as the pin. If you're using oauth for the pin field and the web applicaiton with the password, I would probably use the standard user password for the pin login, as that way you don't need to change the oauth package to work with your new password. Then for your web application build a custom login. To do this create a custom authentication backend along the lines of:
from django.contrib.auth.models import User
from django.contrib.auth.hashers import check_password
class AuthBackend(object):
supports_object_permissions = True
supports_anonymous_user = False
supports_inactive_user = False
def get_user(self, user_id):
return User.objects.filter(pk=user_id).first()
def authenticate(self, username, password):
user = User.objects.filter(username=username).first()
if not user:
return None
# this is checking the password provided against the secondary password field
return user if check_password(password, user.userextension.password) else None
Then you need to add this authentication backend to your settings:
AUTHENTICATION_BACKENDS = ('myapp.backends.AuthBackend',)
Then create the web application login (as per the stackoverflow answer above):
from django.contrib.auth import authenticate, login
def my_login_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
...
else:
# Return an 'invalid login' error message.
...
You should now have a custom authentication login for the web application using your password2 field, and you can use the oauth authentication to work with the standard Django password in which you're going to store the pin. Which I think is what you're trying to do?
NOTE: All of the above I haven't tested, so this may not work perfectly, but it should hopefully be able to at least point you in the right direction and give you a few ideas. If I'm understanding your problem correctly, this is the sort of approach that I would take to tackle the problem.

Want different lookup parameters in django login

I am using django and have email verification feature so when someone verifiy email , I activate his/her account by setting status. If some one will someone else email address then he will not be able to verify and will not able to login with that. So I was expecting django to look at status of user also while login as this status field is in table that is of django auth app. While on login django tries to login with only username param. So on login it says:
MultipleObjectsReturned at /accounts/login/
get() returned more than one User -- it returned 2! Lookup parameters were {'username': u'kaasib122#gmail.com'}
Is there a way to add status field also in lookup? Is there something in cofiguration for that or I need to write some sort of login backend for that? Or should I write my own view for login table in some different way? What is recommended way? Also I am thinking to let user either login using email or username in username field. So what is recommended way?
You need to write an authentication backend that suits your needs. Check out the django documentation.
Basically, you will need to write an "authenticate" method which will use "status" in the filter parameters. For using email or username, you could basically filter on one field (username or email) and if no User objects are returned for that field, filter on the other. Or you can get the user in a single filter by ORing those fields. Here's a pseudocode:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class AuthenticationBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(email=username, status=True)
except User.DoesNotExist:
try:
user = User.objects.get(username=username, status=True)
except User.DoesNotExist:
return None
# check password too
if user.check_password(password):
return user
return None
Note that when you write new authentication backend, you need to add it to AUTHENTICATION_BACKENDS parameter in your settings.py for it to be used. If you don't need the default one Django provides because you have customized it, just override that parameter, no need to add to the tuple.

Looking for a comprehensive guide to setting up custom authentication backends in Django, or pointers

I'm trying to set up a custom backend that queries another database, for which I have created a model in the system. It uses its own rules (email instead of username, and a differently salted/hashed password) so I can't use built in authentication. I've set up a custom authentication backend like so:
class BlahBlahBackend:
def check_password():
# check password code here
return true
def authenticate(self, email=None, password=None):
import myapp.models.loginmodel
try:
person = myapp.models.loginmodel.People.objects.get(email=email)
if check_password(password, person.password):
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
username=person.first_name + person.last_name
name_count = User.objects.filter(username__startswith = username).count()
if name_count:
username = '%s%s'%(username, name_count + 1)
user = User.objects.create_user(username,email)
else:
user = User.objects.create_user(username,email)
except People.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
I've added BlahBlahBackend as an authentication backend:
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
'socialauth.auth_backends.OpenIdBackend',
'socialauth.auth_backends.TwitterBackend',
'socialauth.auth_backends.FacebookBackend',
'socialauth.auth_backends.BlahBlahBackend',
)
As you can see, I'm also using some pre-existing auth backends that are also in socialauth.
I have a submission form that points to the following view:
def blahblah_login_complete(request):
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(email,password)
# if user is authenticated then login user
if user:
login(request, user)
else:
return HttpResponseRedirect(reverse('socialauth_login_page'))
However, when I try to login in this way, it seems like one or more of the other backends are acting as if I'm trying to log in using their method.
I read that backends are cached and so ran
Session.objects.all().delete()
to clear out the backends cache.
My main questions are:
Does the order in which items are listed in AUTHENTICATION_BACKENDS
How does the system decide/know which Backend to use? This was never made clear by any of the documentation, and I find it a bit confusing.
Is there any way to force the use of a specific authorization based on the request. In other words, if someone submits a form, is there a way to force them to use the form-login-based authentication as opposed to the login via openid or Twitter?
Update:
It works! This is very cool, thanks. I guess it just seemed like the django doc was saying "You don't have to do anything else, it just sort of works like magic" and it turns out this is absolutely the case. So long as the backend is there and the credentials are set up correctly, the authentication will work. As it turns out the real problem was a misconfiguration in the urls.py file that wasn't sending the post from the login form to the correct handler, which is why it kept trying to use another authentication method.
You're supposed to use keyword arguments to django.contrib.auth.authenticate() The names should match the names of the arguments in your backend's authenticate method. The default backend handles the names 'username' & 'password'.
Your backend can use a different name for the keyword arguments e.g.: blahblah_email and blahblah_password, and then call authenticate(blahblah_email=..., blahblah_password=...).
It's clearly described here -
django tries each backend in order
defined, if first fails to
authenticate it goes to second etc.
I believe you can load backend class dynamically and authenticate
directly through it. Look at django authenticate() function sources on how to do that.
I guess django-cas will be a good reference for you :)
And yes, the order of AUTHENTICATION_BACKENDS matters.
Django loops over the backends list and stop at the first backend that has a authenticate method accepting the credential parameters you passed to it.