python-social-auth, logout without disconnect - django

Upon logout, wouldn't it be natural to remove the access tokens for social login?
(User will be able to login with different social account next time he logs in)
How do I do it with python-social-auth?
https://python-social-auth.readthedocs.org/en/latest/pipeline.html#disconnection-pipeline talks about disconnecting and I guess it is close to closing the account than to logout
Logout with django-social-auth asks the same question, but answers don't actually address his question.

Just use the default django logout for this, even for login if you see the code inside, it ask the data from OP and create adjango login from that data. and store all the info in socialauth user.
And also python-social-auth have class for socialauth user and storage at backend, which store manythings, so for reference you can check the models.py and storage.py inside social_django.
In my current project which use django and social-auth-app-django of python-social-auth, i am usein gthe default django logout,
from django.contrib.auth import logout as auth_logout
class logout(TemplateView):
next_page = settings.LOGOUT_REDIRECT_URL
redirect_field_name = REDIRECT_FIELD_NAME
template_name = None
extra_context = None
#method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
auth_logout(request)
next_page = settings.LOGOUT_REDIRECT_URL
if next_page:
return HttpResponseRedirect(next_page)
return super().dispatch(request, *args, **kwargs)

Related

Django : How can we custom login_required decorator?

I want to write a decorator like the login_required decorator of Django to check the Azure AD authentication and the Django authentication at the same time. If one of the two is not true, it redirects to the login page.
For the authentication, I used the tutorial (https://learn.microsoft.com/en-us/graph/tutorials/python). I do not how to deal with groups and permissions since I use Azure AD authentication. So I take the username and surname from the token that comes from the Azure Authentication and with this two infos, I create an user in the User Django models. I know it is not the best idea, but I can start to play with groups and permissions.
The django authentication is automatic without that the user create it. It is done in the callback function.
def callback(request):
# Make the token request
result = get_token_from_code(request)
#Get the user's profile
user = get_user(result['access_token'])
# Store user
store_user(request, user)
# Get user info
# user attribute like displayName,surname,mail etc. are defined by the
# institute incase you are using single-tenant. You can get these
# attribute by exploring Microsoft graph-explorer.
username = user['displayName']
password = user['surname']
email = user['mail']
try:
# if use already exist
user = User.objects.get(username=username)
except User.DoesNotExist:
# if user does not exist then create a new user
user = User.objects.create_user(username,email,password)
user.save()
user = authenticate(username=username,password=password)
if user is not None:
login(request,user)
messages.success(request,"Success: You were successfully logged in.")
return redirect('home')
return redirect('home')
If I want to check if the user is authenticated by Azure AD. From the tutorial, I should do something like that :
if request.session.get('user').get('is_authenticated') :
But I do not know how to combine with the django authentication to check both. Anyone can help me
Thanks
simplest way would be to use the user_passes_test decorator to make your own function and apply that as a decorator to your views as per the docs
from django.contrib.auth.decorators import user_passes_test
def check_azure(user):
# so something here to check the azure login which should result in True/False
return #theResult of your check
#user_passes_test(check_azure)
def my_view(request):
...
Here is my solution :
from django.shortcuts import redirect
def authenticated_user(view_func) :
def wrapper_func(request, *args, **kwargs):
if request.user.is_authenticated and request.session.get('user').get('is_authenticated') :
return view_func(request, *args, **kwargs)
else :
return redirect('login')
return wrapper_func

How to create custom login decorators in django

I am creating an app in django where all the authentication like login signup is done by using an exernal rest api so there is no database involved in it. This is why I am saving logged in user data in request.session now the issue is I don't want to show some of the pages if the user is not inside the sessions, what we usually do back in django apps is use #login_required decorator but now as there is no database so what will be the procedure of not showing those pages to not logged in users. thanks
You can define a decorator that will look for a key in the request.sessions:
# app_name/decorators.py
from django.shortcuts import redirect
from functools import wraps
def session_login_required(function=None, session_key='user'):
def decorator(view_func):
#wraps(view_func)
def f(request, *args, **kwargs):
if session_key in request.session:
return view_func(request, *args, **kwargs)
return redirect('name-of-login-view')
return f
if function is not None:
return decorator(function)
return decorator
here it will thus check if 'user' is a key in the request.session. You can of course change this to a different key.
Then we use the decorator for these views:
# app_name/views.py
from app_name.decorators import session_login_required
#session_login_required
def my_view(request, some, parameters):
# …

How can I disallow the user to go to the register page when he is already logged in? Django 2.1.2

I made an admin panel in django. Which consists of login registration and dashboard for admin but i am facing a problem that:
If suppose a user is logged in to the system, and then the user goes to the url and go to register page using the url for ex. localhost/register when he is already logged in and no need of going to register page to register another user account. I don,t want this to happen.
How can I disallow the user to go to the register page when he is already logged in. How can we resolve this issue? Please help
You can try like this:
def register(request):
if request.user.is_authenticated:
return redirect('/') # or reverse('home_url_name')
else:
....
Update from comments:
You need to override LoginView for adding this functionality in login as well, for example:
from django.contrib.auth import views as auth_views
class CustomLoginView(auth_views.LoginView):
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('/')
return super(CustomLogin, self).get(request, *args, **kwargs)
# URL
path('accounts/login/', CustomLoginView.as_view()),

What is the point of having "logout" endpoint in django-rest-auth?

I this article I have read that token based authentication is stateless, meaning that the servers don't keep record of logged in users.
On the other hand in the django-rest-auth API docs there is a logout endpoint mentioned. What is it for?
During log out, the authentication token issued to the user is deleted. You can check out the logout source where it calls request.user.auth_token.delete(). Therefore, the next time the user logs in, a new token will be issued.
In the event you are using the JWT option with django-rest-auth, the logout behavior doesn't actually appear to delete the JWT tokens. So it seems to be essentially doing nothing. Now I'm still new to JWT, but based on what I've learned - it appears that this isn't even necessary. So just delete on the client and you'll be okay. Still it would be nice to have a JUST-DESTROY-THE-JWT-TOKEN-BECAUSE-WHO-NEEDS-POTENTIALLY-UNEXPIRED-DANGEROUS-STUFF-HANGING-AROUND option. But sadly, I don't think rest_framework_jwt supports this.
rest_framework_simplejwt (https://github.com/davesque/django-rest-framework-simplejwt) does seem to support this "blacklisting" which is promising! (rest_framework_simplejwt.token_blacklist) And yet, alas rest_auth does not support simplejwt, straight up - ah well. If someone figures out how to do this, I'd be game.
But back to what's going on with rest-auth's jwt implementation...
So when you are logging out, it does attempt to delete the django token, but I don't believe that's what you are doing here since you should have the following in your settings.py if you are using the JSONWebTokenAuthentication class:
settings.py (for JWT)
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # USED BY JWT.
'rest_framework.authentication.TokenAuthentication', # IGNORED BY JWT
)
Now when django-rest-auth goes to execute /logout, let's see what they are doing from their source code on https://github.com/Tivix/django-rest-auth/blob/master/rest_auth/views.py
views.py (from rest-auth source)
from django.contrib.auth import (
login as django_login,
logout as django_logout
)
from .models import TokenModel
#-------snip-------
class LogoutView(APIView):
"""
Calls Django logout method and delete the Token object
assigned to the current User object.
Accepts/Returns nothing.
"""
permission_classes = (AllowAny,)
def get(self, request, *args, **kwargs):
if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False):
response = self.logout(request)
else:
response = self.http_method_not_allowed(request, *args, **kwargs)
return self.finalize_response(request, response, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.logout(request)
def logout(self, request):
try:
request.user.auth_token.delete()
except (AttributeError, ObjectDoesNotExist):
pass
if getattr(settings, 'REST_SESSION_LOGIN', True):
django_logout(request)
response = Response({"detail": _("Successfully logged out.")},
status=status.HTTP_200_OK)
if getattr(settings, 'REST_USE_JWT', False):
from rest_framework_jwt.settings import api_settings as jwt_settings
if jwt_settings.JWT_AUTH_COOKIE:
response.delete_cookie(jwt_settings.JWT_AUTH_COOKIE)
return response
models.py (from rest-auth source)
from django.conf import settings
from rest_framework.authtoken.models import Token as DefaultTokenModel
from .utils import import_callable
# Register your models here.
TokenModel = import_callable(
getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel))
So unless you've set the REST_AUTH_TOKEN_MODEL attribute in your settings to a custom token model (see https://github.com/Tivix/django-rest-auth/blob/master/docs/configuration.rst - which is doubtful, let's all be honest here. Who is doing this...), then it's just trying to delete the DefaultTokenModel - which is the django_token/session authentication model we aren't using.
I do hope things migrate to simplejwt as it's much more actively supported.
And I also hope this brain-dump/jwt digging helps someone.
P.S. A little more on JWT, optimal uses and blacklisting. https://dev.to/_arpy/how-to-log-out-when-using-jwt-4ajm

Django - allauth - Prevent an unauthenticated user to view pages meant for authenticated users

I am trying to use Django with allauth trying to create a login page.
I am able to login and redirect the user to LOGIN_REDIRECT_URL (= "/users/{id}/mypage") page successfully. I have a separate view for /users/{id}/mypage called the UserHomePageView as defined in views.py:
from django.views.generic import TemplateView
class UserHomePageView(TemplateView):
template_name = "user_homepage.html"
I want a security measure to prevent anyone (basically non-loggedin-users) to navigating to "/users/{id}/mypage" (e.g /users/5/mypage). e.i If unauthenticated user tries to navigate to /users/5/mypage, he/she should get redirected to signin page/homepage.
Basically, how do i present a unauthenticated user to view pages that are meant for authenticated users (I don't want to use template tags users.authenitcated, but wish to override the TemplateView)
Another solution which is generally used is to decorate the dispatch method with the login_required decorator:
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
class UserHomePageView(TemplateView):
template_name = "user_homepage.html"
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(UserHomePageView, self).dispatch(*args, **kwargs)
This has the advantage that it works with all methods (get, post, put, etc.), and that using the login_required decorator is more DRY than explicitly checking request.user.is_authenticated and redirecting.
I found the answer...
By overriding get() and using self.request.user.is_authenticated()
class UserHomePageView(TemplateView):
template_name = "user_homepage.html"
redirect_field_name = "next"
def get(self, request, *args, **kwargs):
'''
Overriding TemplateView.get() in order to
prevent unauthorized user to view UserHomePageView
'''
# Redirect to Homepage if user is not signed in
if not self.request.user.is_authenticated():
return redirect(self.get_redirect_url())
# Process normally if User is signed in
context = self.get_context_data(**kwargs)
return self.render_to_response(context)