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.
Related
To give a user the ability to login to the Django Admin, we set their staff flag.
Is there a way to make a "staff" Group where everyone put into it gains access to the admin page without manually setting staff status?
You can override the Django Admin site (follow the doc, it's pretty amazing).
During the time, create a custom admin site class and override it's has_permission(...) method
from django.contrib import admin
class MyCustomAdminSite(admin.AdminSite):
def has_permission(self, request):
has_perm = super().has_permission(request)
if has_perm:
return True
return request.user.groups.filter(name="YourGroupName").exists()
I have a Django REST backend, and it has a /users endpoint where I can add new users through POST method from frontend.
/users endpoint url:
http://192.168.201.211:8024/users/
In this endpoint I can view all users information and add new user, so I must avoid others entry it except Administrator. I create a superuser admin with password admin123 by python manage.py createsuperuser.
My question is, If I want to do a HTTP POST from frontend(I use Angular) I have to pass the Administrator's user name and password, admin and admin123, along with POST head information. So I let others know the user name and password who check the source code of frontend.
Is there any other way to do this Authentication without exposing Administrator's user name and password to others?
You need to create an API that handles the user creation. This is why we create backends. The user will send the API their credentials and the API will add the user to the database using the admin credentials and post request. The API's code will not be viewable. Depending on your needs, auth0 can be a good solution and save you time on user registration and login. If you make your own sign up and login be sure to hash passwords and make sure they are sent over SSL. A service like auth0 will handle all this for you if you want to focus on other parts of your project.
token auth is may what you need,i use token auth for DRF as backend and angular as frontend
Finally, I find a method to solve this problem.
Here has a very elegant way to do this, rewrite get_queryset function in my UserViewSet:
class UserViewSet(viewsets.ModelViewSet):
# permission_classes = (permissions.IsAdminUser, )
permission_classes = (permissions.AllowAny, ) # <-- change 1
# queryset = User.objects.all() # <-- change 2
serializer_class = UserSerializer
def get_queryset(self):
queryset = User.objects.filter(id=self.request.user.id)
if self.request.user.is_superuser:
queryset = User.objects.all()
return queryset
In change 1, permissions allowed anyone to access, so a new user can do a POST without any authentication.
In change 2, I only return all users when the user is superuser, just like rewrote get_queryset done.
Also need to change urls.py file to add base_name for this url like this:
router.register(r'users', UserViewSet, base_name='user')
ref, https://stackoverflow.com/a/22767325/2803344
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.
I have a django project in which there are multiple profile models, each having a foreign key to the User model. It uses django-allauth for registration.
Currently, when registering using a social account, the user registers, a User and a socialaccount is created, then the user is redirected to a form to fill out, depending on what profile type s/he chose earlier, and after filling out that form is the correct profile type created.
I'd like it if the user, socialaccount and profile type instances are created in the same step, that is after the user fills out the profile specific form. Is there anyway I can do this without changing allauth's code? It wouldn't be too hard to do this by modifying allauth, but I'd rather not maintain a custom copy of a 3rd party app if it can be helped.
Using a custom adapter is out, because it does not have access to the request.
Take a look at the allauth.account.signals.user_signed_up signal, which is triggered just after the user (social or normal) signs up. You can do your stuff with your account there:
from django.dispatch import receiver
from allauth.account.signals import user_signed_up
#receiver(user_signed_up)
def do_stuff_after_sign_up(sender, **kwargs):
request = kwargs['request']
user = kwargs['user']
# Do your stuff with the user
user.save()
From django-allauth repo:
# Typically followed by `user_logged_in` (unless, e-mail verification kicks in)
user_signed_up = Signal(providing_args=["request", "user"])
To learn how to use signals in django, read the official documentation about it.
I hope it helps you!
EDIT
I'm glad you found your way through your problem, but since middlewares are loaded always, I would suggest using the approach I proposed. The socialaccount module from django-allauth also provide signals. Among them, you can find the allauth.socialaccount.signals.social_account_added:
# Sent after a user connects a social account to a his local account.
social_account_added = Signal(providing_args=["request", "sociallogin"])
With a handler similar to the previously written, you can check the user model for the required fields, and then call the redirect shortcut, or return an HttpResponseRedirect object that redirects to the view that shows/handle your form.
I have 2 apps, Registration and Albums. If the user visits the '/' or '/home' then they should see either the registration/login form or their album management page depending on whether the user is logged in or not.
Is there an established best practice for how to dispatch a similar URL between 2 different apps? Is there a way to build this so that either App does not need to know about the other?
Thanks!
If your needs are restricted to showing a login form if the user is not logged in vs showing the "home page" when the user is not logged in, I'd recommend that you use the "login required" decorator.
from django.contrib.auth.decorators import login_required
#login_required
def show_home(request):
"""
Show home page...
"""
...
This decorator can be applied at the view level ( as shown above ) or in urls.py ( as shown below ):
url(r'^reports/', login_required(ListView.as_view(
template_name="...",
queryset = ...,
context_object_name = ...
))),
The second pattern is commonly used with generic views and class based views.
Both solutions presuppose that you are hooking into Django's built in login / registration apparatus ( with customized templates and customized views where needed ). If you are using a custom registration / auth framework, it will still be a good idea to use a decorator pattern.
If you set LOGIN_URL to /registration/login, and decorate your / view with #login_required, then they will automatically be redirected.
when user signs-in add a variable to session and check it on the / or /home request.