How to create custom django validation for authentication - django

Hi everyone) I'm new in Django. I need to do a really simple validation for sign in form. In my app can sign in only one user, with a specific username and password, for example, "my_username" and "my_password". And superuser can't sign in. I don't know do I even need a table in a database for only one user?
By now I write a simple login form with django.contrib.auth.views LoginView and this work, but for everyone who is in database and superuser.

From the django admin page create a new user.
Then if you want to allow only this user in some view just add this decorator:
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda user: user.username == 'allowed_username')
def my_view(request):
# your code

Related

Django allauth - Signing up a new user while already logged in

I'm trying to customize allauth's default SignUpView and SignUpForm to allow me to create other users while already logged in. The default behavior prevents me from doing this: in other words, I can only sign up for a new account if I'm not authenticated.
How do I override this behavior?
I presume I'll have to override the SignupView in views.py but I'm not sure what to look for... I played around with RedirectAuthenticatedUserMixin, but to no avail.
Forms.py
from allauth.account.forms import SignupForm
class SubUserForm(SignupForm):
USER_TYPES = [
(2,'customer'),
(3,'vendor'),
(4,'supplier')
]
first_name = forms.CharField(max_length=45)
last_name = forms.CharField(max_length=45)
user_type = forms.CharField(widget=forms.Select(choices=USER_TYPES))
Views.py
from allauth.account.views import SignupView
class SubUserSignupView(SignupView):
template_name = 'accounts/new_user_signup_form.html'
form_class = SubUserForm
view_name = 'sub_user_signup'
sub_user_signup = SubUserSignupView.as_view()
urls.py
urlpatterns = [
path('sub_user/',views.sub_user_signup,name='sub_user_signup'),
]
To put in context
My app allows for a 'parent' user to sign up multiple 'children' users (called 'subuser' in the code above) using allauth. In my case, an organization can create several customers, merchants, suppliers, etc. When a parent user creates a child user, a verification email is sent to the child user, who then activates his account and is prompted to enter a password. I use 2 signup forms; the default allauth signup (for parent accounts), and a customized signup form (for children accounts), which also extends from allauth.
Although the registration flow above works well, a parent user can only sign up new children users (trigger email verification) when logged out. I'm struggling to identify what I need to prevent this from happening.
Navigate to the allauth directory, under app settings, set this to False
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS (=True)
The default behaviour is to redirect authenticated users to LOGIN_REDIRECT_URL when they try accessing login/signup pages.
By changing this setting to False, logged in users will not be redirected when they access login/signup pages.
This also worked
Navigate to the allauth folder, under views find SignupView.
Deleting the redirectAuthenticatedUsermixin works
New issue is that you are logged in as the new user, fixing that currently.
First of all, this article maybe useful:
https://tech.serhatteker.com/post/2020-06/custom-signup-view-in-django-allauth/
The reason you can only sign up for a new account if you're not authenticated is because of this Allauth's mixin: RedirectAuthenticatedUserMixin (as suggested by Anthony M).
So, you have to override this mixin and the allauth's signup view with your own code.
It is very important that you register the url before allauth urls.
Hope it helps.

django user auth without typing password

I want a feature workflows as follows:
1) user login from web page ( typing user name/password),and auth success, then we can got user's password from database(not from web page), we will use it later.
2) user confirm start a small bot service that provide by us, once user confirm that, then the service will execute and callback
3) since the bot service is another independent app, so it have to use user account callback login action (auth) and record information under the user account.
my question is, while I use the user's account login in bot service app, it failed, since the password has been hash.
is there any way solve this issue ?
I trace django source code ,
djanofrom django.contrib import auth
auth.login(request,authenticate)
seem no other way solve this issue unless modify the source code, I meaning add new function in framework? but obviously, it is not best idea
anyone give tips on this issue, thanks
You should write a custom auth backend.
https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class PasswordlessAuthBackend(ModelBackend):
def authenticate(self, username=None):
try:
return User.objects.get(username=username)
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
then add this to your settings.py
AUTHENTICATION_BACKENDS = (
# ... your other backends
'yourapp.auth_backend.PasswordlessAuthBackend',
)
after that you can login in your views with
user = authenticate(username=user.username)
login(request, user)

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.

How to Redirect to user profile in django? i am using Django registration Redux

I am working on an app where the user will be able to login to his profile. I am using Django-registration-redux. I am using the below code to inculde in my project.
LOGIN_REDIRECT_URL = '/profile/view/(?P<pk>[0-9]+)/'
I want to redirect the user to his profile after logging in. I know that is not the way you can actually call an url in settings file. any solution for the problem?
I believe you can use https://docs.djangoproject.com/en/dev/ref/urlresolvers/#reverse-lazy to add URL resolution to a setting.
You don't need to pass the user pk to the view. You can get this value and every other data field of the user from request.user object.
As stated in Django docs, you could do something like this:
def profile(request):
if request.user.is_authenticated:
# Do something for logged-in users.
request.user.do_something()
[...]
else:
# Do something for anonymous users like redirect to registration
pass

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.