Django-Allauth, Multiple login redirect url - django

I have a question, how can I add more than one LOGIN_REDIRECT_URL in settings or in views for my differents users.
For example, I have: Administrators, Human Resources, Teachers, students... etc
and for each I need redirect to a different url, panel admin for Admin etc.
I need add groups? or not?
Thanks for your help!

django-allauth get the login redirect URL from method get_login_redirect_url defined in account adapter you can define your custom adapter and override this:
my_app/adapter.py
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
url = super(AccountAdapter, self).get_login_redirect_url(request)
user = request.user
'''
# pseudocode, change it to actual logic
# check user role and return a different URL
role = get_user_role(user)
if role == 'student':
url = student_login_redirect_url
if role == 'teacher':
url = teacher_login_redirect_url
'''
return url
Now tell allauth to use our custom adapter by defining the ACCOUNT_ADAPTER in settings.py:
ACCOUNT_ADAPTER = 'my_app.adapter.AccountAdapter'

Related

How to set LOGIN_URL variable in Django settings so it doesn't redirect anywhere while not logged in

When trying to access url get_room_messages if user is not logged in #login_required redirects him to: /accounts/login/?next=/get_room_messages
(as specified in docs)
I want it to do nothing (or redirect to the original url, in this example /get_room_messages). I don't want to hardcode it like #login_required(login_url='/get_room_messages'), ideal solution would be to get somehow original url and pass it into #login_required() decorator.
#login_required()
def get_room_messages(request):
user_id = request.user.user_ID
user = get_object_or_404(CustomUser, pk=user_id)
Thank you for help!

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.

How can i customize login api from djoser package?

I just want to give a user details in a login response,
currently, I'm getting 'token' and 'refresh' in
http://127.0.0.1:8000/auth/jwt/create/ JWT login API response.
I want to return with login user details
here is the response snapshot of jwt/create/,
JWT Response Image
As djoser uses django-rest-framework-simplejwt inside, you have to call your custom view instead of the TokenObtainPairView to add user's details in api response.
You can achieve this through following steps:
your_app/urls.py
You have to create your own custom url in order to customize JWT Create API's response.Add the below url path above the "djoser.urls" path so that this url gets called instead of djoser's package jwt/create url.
from your_app.views import CustomTokenObtainPairView
urlpatterns = [
...
path('auth/jwt/token/', CustomTokenObtainPairView.as_view(), name='custom_token_obtain_pair'),
]
your_app/views.py
Now add your custom view class and its corresponding serializer class where you can add user attributes for your api response.
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
## This data variable will contain refresh and access tokens
data = super().validate(attrs)
## You can add more User model's attributes like username,email etc. in the data dictionary like this.
data['user_name'] = self.user.username
return data
class CustomTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer

Django view visible only to admin

I have a view in my django backend which I want only admin to see.
#api_view(('GET',))
def get_analytics(request):
# Number of users who dogged in once to our system today
login_count= User.objects.filter(last_login__startswith=timezone.now().date()).count()
data = {}
data['login_count'] = login_count
return JSONResponse(data)
It's a function based view. How can I make it visible only to admin? it's corresponding url I hit from my angular app to get and render the data.
You can also use the below decorator
from django.contrib.admin.views.decorators import staff_member_required
#staff_member_required
You can add IsAdminUser permission class to your view to restrict access to only admin users. Only users with admin permissions will be granted access then. Others will be denied access.
#api_view(('GET',))
#permission_classes((IsAdminUser, )) # add the permission class
def get_analytics(request):
...
return JSONResponse(data)
When the permissions fail, then either an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised depending on some conditions.

django-allauth: Only allow users from a specific google apps domain

I am a newbie at Django. Using django-allauth I have set up single click sign in. I obtained my domain credentials ( client_id and secret_key) from google api console. But the problem is django-allauth is letting me login from any google account while I want the email addresses to be restricted to my domain ( #example.com instead of #gmail.com)
django-social-auth has the white listed domains parameter for this, how do I include this information in allauth?
I found django-allauth much easier to set up after spending hours on django-social-auth
Any help would be much appreciated.
Answering my own question-
What you want to do is stall the login after a user has been authenticated by a social account provider and before they can proceed to their profile page. You can do this with the
pre_social_login method of the DefaultSocialAccountAdapter class in allauth/socialaccount/adaptor.py
Invoked just after a user successfully authenticates via a
social provider, but before the login is actually processed
(and before the pre_social_login signal is emitted).
You can use this hook to intervene, e.g. abort the login by
raising an ImmediateHttpResponse
Why both an adapter hook and the signal? Intervening in
e.g. the flow from within a signal handler is bad -- multiple
handlers may be active and are executed in undetermined order.
Do something like
from allauth.socialaccount.adaptor import DefaultSocialAccountAdapter
class MySocialAccount(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
u = sociallogin.account.user
if not u.email.split('#')[1] == "example.com"
raise ImmediateHttpResponse(render_to_response('error.html'))
This is not an exact implementation but something like this works.
Here's an alternate solution:
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class CustomAccountAdapter(DefaultAccountAdapter):
def is_open_for_signup(self, request):
return False # No email/password signups allowed
class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
def is_open_for_signup(self, request, sociallogin):
u = sociallogin.user
# Optionally, set as staff now as well.
# This is useful if you are using this for the Django Admin login.
# Be careful with the staff setting, as some providers don't verify
# email address, so that could be considered a security flaw.
#u.is_staff = u.email.split('#')[1] == "customdomain.com"
return u.email.split('#')[1] == "customdomain.com"
This code can live anywhere, but assuming it's in mysite/adapters.py, you'll also need the following in your settings.py:
ACCOUNT_ADAPTER = 'mysite.adapters.CustomAccountAdapter'
SOCIALACCOUNT_ADAPTER = 'mysite.adapters.CustomSocialAccountAdapter'
You could do something in the line of overriding allauth's allauth.socialaccount.forms.SignupForm and checking the domain during the signup process.
Discalmer: this is all written without testing, but something in the line of that should work.
# settings.py
# not necesarry, but it would be a smart way to go instead of hardcoding it
ALLOWED_DOMAIN = 'example.com'
.
# forms.py
from django.conf import settings
from allauth.socialaccount.forms import SignupForm
class MySignupForm(SignupForm):
def clean_email(self):
data = self.cleaned_data['email']
if data.split('#')[1].lower() == settings.ALLOWED_DOMAIN:
raise forms.ValidationError(_(u'domena!'))
return data
in your urls override allauth defaults (put this before the include of django-allauth)
# urls.py
from allauth.socialaccount.views import SignupView
from .forms import MySignupForm
urlpatterns = patterns('',
# ...
url(r"^social/signup/$", SignupView.as_view(form_class=MySignupForm), name="account_signup"),
# ...
)
I'm not sure for the "^social/signup/$", recheck that.