Django Auth Additional Validation - django

I need compare a boolean variable when I do login (variable name: approved)
If variable is true:
login success; 7
else
login error;
I have variable stored in database.
My form:
class LoginForm(AuthenticationForm):
username (...)
password (...)
Urls:
`url(r'^login/$', auth_views.login, {'authentication_form': LoginForm},` `name='login'),`
Views:
def login(request):
return render(request, 'registration/login.html')
How to change default login to allow this?

Limit access based on certain permissions
There's a really nice way to check if some "test" is passed. In your example, a "test" would be if approved variable is True. You can do something like this:
from django.contrib.auth.decorators import user_passes_test
def check_approved():
# get the approved variable from database
approved = True # or false, depends on what you read from the database
return approved
#user_passes_test(check_approved)
def login(request):
...
So, #user_passes_test() decorator receives a callback which must return True or False. You can read more about it in the docs.
If this doesn't help you, please elaborate a bit more on what you would like to do exactly and why this method can't help you.

Related

django-allauth - Critical login required : Allow users stored in a database only to login

I have implemented login form for username/password method, and that works perfect.
I want user to be also able to login using their social accounts.
I am using django-allauth to map social users to django-users.
Now I want to allow only those social accounts to login, that are mapped to django-users and not everyone.
Is there a way to override callback view? or something else can be done?
To simply disable registration, you have to overwrite the default account adaptor. If you also want to support social login, you also need to overwrite the default soculaaccount adapter. Add the following code somewhere in one of your apps (e.g. adapter.py):
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
class NoNewUsersAccountAdapter(DefaultAccountAdapter):
def is_open_for_signup(self, request):
return False
class SocialAccountWhitelist(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
u = sociallogin.user
print('User {0} is trying to login'.format(u.email))
# Write code here to check your whitelist
if not_in_your_list(u):
raise ImmediateHttpResponse(HttpResponseRedirect('/account/login'))
and then add the following to your settings:
ACCOUNT_ADAPTER = 'path_to_app.adapter.NoNewUsersAccountAdapter'
SOCIALACCOUNT_ADAPTER = 'path_to_app.adapters.SocialAccountWhitelist'
After that, all you need to do is manually create an Account from the Admin pages, and manually create an EmailAddress. For the social login, you will need to write code to somehow check if the email is allowed
I would recommend you add a Staff-Only form to make this easy on you, where you can ask for username, email (and even password) and then do
new_user = Account.objects.create_user(email=email, username=username, password=password)
EmailAddress.objects.create(email=email, user=new_user, verified=True, primary=True)
You can also develop an Invitation scheme, but that is a lot more complicated but quickly googled and found the following project, which I have not personally used, but looks like what you need:
https://github.com/bee-keeper/django-invitations
Finally After reading the documents thoroughly and doing a lot of trials and errors I got to what I was looking for.
I had to set following parameters as a part of configuration specified in docs.
ACCOUNT_EMAIL_REQUIRED (=False)
The user is required to hand over an e-mail address when signing up.
and
SOCIALACCOUNT_QUERY_EMAIL (=ACCOUNT_EMAIL_REQUIRED)
Request e-mail address from 3rd party account provider? E.g. using OpenID AX, or the Facebook “email” permission.
I had to set ACCOUNT_EMAIL_REQUIRED = True as it was required to check if that email id is already registerd with us.
and then finally I overridden pre_social_login like below.
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class NoNewSocialLogin(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
try:
cr_user = auth_user.objects.get(email=sociallogin.user.email)
if cr_user and cr_user.is_active:
user_login = login(request, cr_user, 'django.contrib.auth.backends.ModelBackend')
raise ImmediateHttpResponse(HttpResponseRedirect(reverse('protect')))
else:
raise ImmediateHttpResponse(render_to_response("account/authentication_error.html"))
except ObjectDoesNotExist as e:
raise ImmediateHttpResponse(render_to_response("socialaccount/authentication_error.html"))
except Exception as e:
raise ImmediateHttpResponse(HttpResponseRedirect(reverse('protect')))

Create a User Profile or other Django Object automatically

I have setup a basic Django site and have added login to the site. Additionally, I have created a Student (Profile) model that expands upon the built in User one. It has a OneToOne relationship with the User Model.
However, I have yet not come right with forcing the user to automatically create a Profile the first time they log in. How would I make sure they are not able to progress through anything without creating this?
I have tried by defining the following in views:
def UserCheck(request):
current_user = request.user
# Check for or create a Student; set default account type here
try:
profile = Student.objects.get(user = request.user)
if profile == None:
return redirect('/student/profile/update')
return True
except:
return redirect('/student/profile/update')
And thereafter adding the following:
UserCheck(request)
at the top of each of my views. This however, never seems to redirect a user to create a profile.
Is there a best way to ensure that the User is forced to create a profile object above?
Looks like you're attempting to do something similar to Django's user_passes_test decorator (documentation). You can turn the function you have into this:
# Side note: Classes are CamelCase, not functions
def user_check(user):
# Simpler way of seeing if the profile exists
profile_exists = Student.objects.filter(user=user).exists()
if profile_exists:
# The user can continue
return True
else:
# If they don't, they need to be sent elsewhere
return False
Then, you can add a decorator to your views:
from django.contrib.auth.decorators import user_passes_test
# Login URL is where they will be sent if user_check returns False
#user_passes_test(user_check, login_url='/student/profile/update')
def some_view(request):
# Do stuff here
pass

HttpResponseRedirect not working Django 1.7

I am having a problem with HttpResponseRedirect in Django. It seems that, whatever parameters I try, it either throws an error, or it redirects without changing the URL. I am using it on a custom login_user view, and I want the URL in the address bar to change after they are redirected. If I use redirect instead of HttpResponseRedirect, it does not change. Either way, I can get it to serve the correct template, but the URL stays the same. Being new to Django, it would be helpful if someone could explain to me how to do this and why my current code is not working.
I have seen a couple of similar questions to mine on Stack Exchange, but the answers have not helped.
Here are the relevant parts of my views.py (please note the indenting has gone weird due to copying and pasting in here, and is not the cause of the error).
from django.http import *
from django.contrib.auth import authenticate, login, logout
def login_user(request):
logout(request)
username = password = ''
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('dashboard')
else:
state = "Your account is not active, please contact the app administrator."
else:
state = "Your username and/or password were incorrect."
state = "Please log in below..."
context = RequestContext(request, {
'state': state,
'username': username,
})
return render_to_response('bank/auth.html', {}, context)
dashboard is the name of another view, and it works fine in a redirect from my index view. I've also tried hard-coding the url in, but that doesn't work either. Any suggestions?? Thanks.
If you use HttpResponseRedirect, you must provide the url, not the name of the url.
You can either get the url by using reverse:
from django.core.urlresolvers import reverse
def my_view(request):
...
return HttpResponseRedirect(reverse('dashboard'))
or by using the redirect shortcut.
from django.shortcuts import redirect
def my_view(request):
...
return redirect('dashboard')
If using the either of the above approaches does not work, then there's probably a mistake somewhere else in the view. It's difficult to tell where, since the indentation is incorrect. Try adding some logging or print statements to see if you are really returning the redirect where you think you are.
In this particular case, the problem wasn't anything to do with my view code, it was actually a problem caused through using JQuery mobile. I found the answer here: Error with Redirects in JQuery Mobile which was to set the data-url attribute on the page div.
However, I have up-voted Alasdair's answer, as his way is the correct one of the ways I had tried.
I personally prefer the simple way as follows:
In urls.py:
url(r'^dashboard/$', 'appname.views.dashboard_view', name='dashboard_view'),
In views.py:
from django.http import HttpResponseRedirect
def dashboard_view(request):
...
return HttpResponseRedirect('/dashboard/')

Doing User Profiles In Django

I'm trying to set up user profiles in my site so we have:
www.example.com/someuser
www.example.com/anotheruser2
in my urls.py
url(r'^(?P<profile>[0-9A-Fa-f]{1,36})/', 'site.views.profile),
and my view:
def profile(request, profile):
... do something ...
There are two questions:
Is this the correct way to do this or is there a better way?
How should I handle other urls, like "aboutus", etc.
For Point 2, I would do:
url(r'^aboutus/', 'site.views.aboutus'),
url(r'^(?P<profile>[0-9A-Fa-f]{1,36})/', 'site.views.profile),
So now profile will be the catchall for everything else in the site, and I have to check for a valid profile then throw a 404 if a password is not found.
Again, is there a better way to do this?
It's not a good idea to use site.views.profile as a catchall. It's not good separation of responsibilities, it shouldn't be its job. How about something like this instead:
url(r'^profile/$', 'site.views.profile_self'),
url(r'^profile/(?P<profile_name>[0-9A-Fa-f]{1,36})/$', 'site.views.profile'),
url(r'^aboutus/', 'site.views.aboutus'),
For the catchall, use a custom 404 page, or you could let the server raise a 404 error.
accounts/models.py
from django.db import models
class User():
def get_profile(self):
return UserProfile.objects.get_or_create(user_id=self.id)
class UserProfile(models.Model):
user = models.OneToOneField(User)
# another fields
accounts/urls.py
url(r'^profile/$', 'site.views.profile'),
accounts/views.py
from django.contrib.auth.decorators import login_required
#login_required
def profile(request):
# get current logged user profile
profile = request.user.get_profile()
this way the user logged only can see his own profile.
and for the point 2, what's wrong with this?
url(r'^about_us/$', 'site.views.about_us'),
--UPDATE--
ah, ok. then, you are right. but why not with the username?
accounts/urls.py
url(r'^(?P<username>[-\w]+)/$', 'site.views.profile'),

How can I redirect a user to a specific page or run some code logic in a common place after login in Django?

What I want is to redirect the user to a specific page when they log in if a flag is raised. So I know that all of the login requests go through django.contrib.auth.views.login. Do I have to modify this to accomplish what I want to do or is there some other way to do this. So when I log in I hit the index page and that's fine, I can work with that but what if the user tries to access a page where log in is required. Here's what it will look like
login/?next=/page_that_requires_login
so now after login, it will not hit the index page anymore, it will go directly to page_that_requires_login. I am a little new to django but my instinct tells me that I shouldn't have to check this flag on every page. Is there a common place that I can do some code logic after a user is logged in no matter what page they get redirect to?
Django provides decorator called, login_required() which we can attach to any view, where we require the user to be logged in. If a user is not logged in and they try to access a page which calls that view, then the user is redirected to another page which you can set, typically the login page.The following is an example code for a view called restricted.
#login_required
def restricted(request):
return HttpResponse("since you are logged in you can see this page)
Note that to use a decorator, you place it directly above the function signature, and put a # before naming the decorator. Python will execute the decorator before executing the code of your function/method. To use the decorator you will have to import it, so also add the following import:
from django.contrib.auth.decorators import login_required
To set a page to which the user is redirected if he is not logged in, you need to add the something like this to settings.py
LOGIN_URL = "/app_name/login/"
This ensures that the login_required() decorator will redirect any user not logged in to the URL /app_name/login/.
I redirected by groupwise as :
from django.http import HttpResponseRedirect
def loggedin_view(request):
usergroup = None
if request.user.is_authenticated():
usergroup = request.user.groups.values_list('name', flat=True).first()
if usergroup == "staffGroup":
return HttpResponseRedirect("/cmit/userDash")
elif usergroup == "supervisorGroup":
return HttpResponseRedirect("/cmit/supervisorDash")
elif usergroup == "auditGroup":
return HttpResponseRedirect("/cmit/auditDash")
elif usergroup == "mgtGroup":
return HttpResponseRedirect("/cmit/mgtDash")
else:
return HttpResponseRedirect("/admin/")