Django REST: AttributeError: 'WSGIRequest' object has no attribute 'session' - python-3.x

I've created a Login APIView for my Django app. I'm continually getting the error, AttributeError: 'WSGIRequest' object has no attribute 'session'. I've looked at other posts and people mention reordering the middleware placing sessionMIddleware first which doesn't work. Here is the setup of the API. The error is occurring at login(request, user).
from django.contrib.auth import authenticate, login
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import LoginSerializer
from rest_framework.permissions import AllowAny
class Login(APIView):
permission_classes = (AllowAny, )
authentication_classes = ()
serializer = LoginSerializer
def post(self, request, format=None):
login_form = self.serializer(data=request.data)
data = dict()
if login_form.is_valid():
username = login_form.data['username']
password = login_form.data['password']
user = authenticate(username=username, password=password)
if user is not None:
print(request.data)
login(request, user)
data['data'] = 'OK'
return Response(data=data, status=200)
else:
data['error'] = 'Invalid login information provided'
return Response(data=data, status=401)
else:
data['invalid'] = 'Bad Request, form is invalid'
return Response(data=data, status=400)

Ok, I had my middleware defined as MIDDLEWARE in my settings.py instead of MIDDLEWARE_CLASSES. Pycharm generated it for me like that when I setup the new project. I believe Django 1.10 uses MIDDLEWARE and I'm using 1.9.

Related

How to Refresh a OAuth2 Token by using Django OAuth Toolkit in custom Views?

What I'm doing?
I have a requirement where there will be separate authorisation server and a resource server.
I am using Resource owner password based grant type.
I have implemented Custom Introspection View and Get Token View. (Following this and this: I have used the DOT's base class to implement my own introspection API, will add it at the end.)
For both Custom Views I created, I have added it to the urls.py manually referring to it.
What's happening now?
Turns out, you gotta refresh token using the same /token/ url which you used to get a access token. The only difference is you gotta change the grant type to refresh_token when you wanna refresh token.
It does not get processed as I have not implemented or am able to implement the refresh token. I am happy with the pre-existing internal refresh token mechanism as I don't require special/custom stuff to be in it but as I'm using a custom token view, grand_type = refresh_token is not hitting the oauthlibs refresh_token view. (My observation)
urls.py
from django.contrib import admin
from django.urls import path, include
from project.apis import (
ClientCreateTokenView,
ResourceServerIntrospectView
)
urlpatterns = [
path('admin/', admin.site.urls),
path('o/token/', ClientCreateTokenView.as_view(), name='token_obtain_pair'),
path('o/introspect/', ResourceServerIntrospectView.as_view(), name='introspect_token'),
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]
apis.py
from django.http import HttpResponse
from oauth2_provider.views.base import TokenView
from oauth2_provider.views import IntrospectTokenView
from django.utils.decorators import method_decorator
from django.views.decorators.debug import sensitive_post_parameters
from oauth2_provider.models import get_access_token_model
from oauth2_provider.signals import app_authorized
import json
from iam_management.models import AuthorisedClients
from rest_framework import status
from base64 import b64decode
from django.contrib.auth.models import User
import time
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse
import calendar
class ResourceServerIntrospectView(IntrospectTokenView):
"""
Implements an endpoint for token introspection based
on RFC 7662 https://tools.ietf.org/html/rfc7662
"""
#staticmethod
def get_token_response(token_value=None, resource_server_app_name=None):
try:
token = (
get_access_token_model().objects.select_related("user", "application").get(token=token_value)
)
except ObjectDoesNotExist:
return JsonResponse({"active": False}, status=200)
else:
authorised_clients = AuthorisedClients.objects.filter(user=token.user).first()
if token.is_valid() and resource_server_app_name in json.loads(authorised_clients.authorised_apps):
data = {
"active": True,
"exp": int(calendar.timegm(token.expires.timetuple())),
}
if token.application:
data["client_id"] = token.application.client_id
if token.user:
data["username"] = token.user.get_username()
return JsonResponse(data)
else:
return JsonResponse({"active": False}, status=200)
def get(self, request, *args, **kwargs):
return HttpResponse(status=405)
def post(self, request, *args, **kwargs):
"""
Get the token from the body parameters.
Body: { "token": "mF_9.B5f-4.1JqM" }
"""
if "token" in request.POST and "app_name" in request.POST:
return self.get_token_response(request.POST["token"], request.POST["app_name"])
else:
return HttpResponse(status=400)
class ClientCreateTokenView(TokenView):
#method_decorator(sensitive_post_parameters("password"))
def post(self, request, *args, **kwargs):
try:
username = request.POST["username"]
app_name = request.POST["app_name"]
client_id = \
b64decode(request.META["HTTP_AUTHORIZATION"].split(" ")[1].encode("utf-8")).decode("utf-8").split(":")[
0]
except:
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
authorized_client = AuthorisedClients.objects.filter(user=User.objects.get(username=username),
client_id=client_id).first()
if not authorized_client:
return HttpResponse(status=status.HTTP_401_UNAUTHORIZED)
authorised_apps = json.loads(authorized_client.authorised_apps)
if app_name.lower() not in authorised_apps:
return HttpResponse(status=status.HTTP_401_UNAUTHORIZED)
url, headers, body, return_status = self.create_token_response(request)
if return_status == 200:
body = json.loads(body)
access_token = body.get("access_token")
if access_token is not None:
token = get_access_token_model().objects.get(token=access_token)
app_authorized.send(
sender=self,
request=request,
token=token
)
if "scope" in body.keys():
del body["scope"]
body = json.dumps(body)
response = HttpResponse(content=body, status=return_status)
for k, v in headers.items():
response[k] = v
return response
I know that I am not really following the standards and putting custom stuff here for more checks but that's just my use case. I am unable to find anything on refresh token on DOT even though it is a famous and maintained package.

Django custom login issue

I have created a custom authenticate method because instead of username I want to log in through email for that I have written backends.py
backends.py
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
UserModel = get_user_model()
class EmailBackend(object):
def authenticate(username=None,password=None):
try:
user = UserModel.objects.get(email=username)
if user.check_password(password):
return user
else:
return None
except UserModel.DoesNotExist:
raise ValidationError('Invalid Credentials')
def get_user(self,user_id):
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
After authenticating i want user to be logged in.For that i am using login method as below:
login(request,user,backend='django.contrib.auth.backends.ModelBackend')
views.py
from django.shortcuts import render,redirect
from users.forms import RegisterForm,LoginForm
from users.backends import EmailBackend as em
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login
def register(request):
if request.method=='POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
print('Successfully Created')
else:
form = RegisterForm()
return render(request,'users/register.html',{'form':form})
def user_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
uname = request.POST['username']
pwd = request.POST['password']
user = em.authenticate(username=uname,password=pwd)
if user is not None:
if user.is_active==True:
k=login(request,user,backend='django.contrib.auth.backends.ModelBackend')
print(user,k)
print('Successfull login')
else:
print('Unsuccessfull login')
else:
form = LoginForm()
return render(request,'users/login.html',{'form':form})
In my console, I am trying to get the value returned by the login function but that is returning None .
k=login(request,user,backend='django.contrib.auth.backends.ModelBackend')
print(user,k)
Output in my console:
[16/Mar/2021 16:02:34] "POST /register/ HTTP/1.1" 200 881
[16/Mar/2021 16:02:52] "GET /login/ HTTP/1.1" 200 705
testuser#gmail.com None
Successfull login
[16/Mar/2021 16:02:58] "POST /login/ HTTP/1.1" 302 0
[16/Mar/2021 16:02:58] "GET /home HTTP/1.1" 200 237**
Print method is giving the correct value of user but for k it is giving None. That means the login function is not working and that means login authentication is not working properly.
How can I do login once authenticate method is returned, user? In which way login can be successful.
My code:
settings.py
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend',
'users.backends.EmailBackend']
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser,AbstractUser
from django.utils.translation import gettext_lazy as _
class CustomUser(AbstractBaseUser):
email = models.EmailField(_('email address'), unique=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
USERNAME_FIELD='email'
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django import forms
from users.models import CustomUser
class RegisterForm(UserCreationForm):
class Meta():
model = get_user_model()
fields = ('email', 'password1', 'password2')
class LoginForm(AuthenticationForm):
class Meta():
model = get_user_model()
You are doing you login wrong. You are referencing the auth Backend you just overwrote.
In your login function, do
login(request, user)
And in your settings
AUTHENTICATION_BACKENDS = ['users.backends.EmailBackend', 'django.contrib.auth.backends.ModelBackend']
One more thing, do not import your backend. Just import django authenticate module like you would do if weren't having your own backend
And change your authenticate line to
From django.contrib.auth import authenticate
user = authenticate(username=uname, password=pwd)
I got the answer login method has no return value that's why it is returning None. Once authenticate method is executed it will return a user if credentials are valid . After that login method will make you logged in.

Creating User class with Flask-login and PyMongo and retrieving data from MongoDB

Hi guys,
I'm a total noob regarding Python and Flaks. As part of my school project, I need to create user registration/login functionality with Flask and PyMongo.
So basically register a user with the username, email, and user password.
Login user with email and password.
Retrieve from MongoDb user default profile image following with profile date created, user username, and user email.
The way we need to do this is to create a User class.
When a user is successfully login they should see displayed on the front-end their username, email, default profile image, and date when the user profile was created.
Then the user needs to have an option to upload their profile image, username, and email.
Unfortunately, it has to be MongoDB for the database.
My current code is not uploading the User class blueprint to MongoDB and I don't know how to upload the default image and retrieve user info in the profile.html
Can you help me with this, please?
Any useful advice is welcome and if you can fix my code that would be great.
If you need more info let me know.
MY CODE SO FAR:
routes.py
import os
import json
from flask import Flask, flash, render_template, redirect, request, session, url_for
from flask_sqlalchemy import SQLAlchemy
from mongoengine import *
from datetime import datetime
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager
from flask_login import current_user, login_user, logout_user, login_required
from forms import RegisterForm, LoginForm, AddTip, UpdateProfile
if os.path.exists("env.py"):
import env
app = Flask(__name__)
app.config["MONGO_DBNAME"] = os.environ.get("MONGO_DBNAME")
app.config["MONGO_URI"] = os.environ.get("MONGO_URI")
connect("MONGO_DBNAME", host=app.config["MONGO_URI"])
app.secret_key = os.environ.get("SECRET_KEY")
mongo = PyMongo(app)
login = LoginManager(app)
login.login_view = 'login'
login.login_message = "To access your profile, pleas log in!"
login.login_message_category = "log-info"
class User(Document):
username = StringField(unique=True, required=True)
email = EmailField(unique=True)
password = BinaryField(required=True)
age = IntField()
profile_image = ImageField()
registered = BooleanField(default=False)
date_created = DateTimeField(default=datetime.utcnow)
def __init__(self, username, email, date_created):
self.username = username
self.email = email
self.date_created = date_created
#staticmethod
def is_authenticated():
return True
#staticmethod
def is_active():
return True
#staticmethod
def is_anonymous():
return False
def get_id(self):
return self.username
#staticmethod
def check_password(password_hash, password):
return check_password_hash(password_hash, password)
#login.user_loader
def load_user(username):
user = mongo.db.users.find_one({"username": username})
if not user:
return None
return User(user["username"], user["email"], user["date_created"])
THEN MY REGISTER ROUTE:
#app.route("/registration", methods=["GET", "POST"])
def registration():
form = RegisterForm()
if form.validate_on_submit():
user = {
"username" : request.form.get("username").lower(),
"email" : request.form.get("email"),
"password" : generate_password_hash(request.form.get("password"))
}
mongo.db.users.insert_one(user)
session["user"] = request.form.get("username").lower()
flash("Welcome to your new profile", "reg-success")
return redirect(url_for("profile", username=session["user"]))
return render_template("registration.html", title="| Register", form=form)
LOG IN ROUTE:
#app.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect(url_for("home"))
form = LoginForm()
if form.validate_on_submit():
user = mongo.db.users.find_one({"email": form.email.data})
if user and User.check_password(user["password"], form.password.data):
user_obj = User(username=user["username"])
login_user(user_obj)
next_page = request.args.get("next")
return redirect(next_page) if next_page else redirect(url_for("profile"))
else:
flash("Invalid username or password", "reg-danger")
return render_template("login.html", title="| Login", form=form)
PROFILE ROUTE:
#app.route("/profile", methods=["GET", "POST"])
#login_required
def profile():
form = UpdateProfile()
if form.validate_on_submit():
flash("Your details are updated", "reg-success")
else:
flash("Pleas check your details", "reg-danger")
return render_template('profile.html', title='| Profile', form=form)

Flask-Login using Radius

I am trying to setup Flask-Login where the user database is on a RADIUS server.
I can validate credentials just fine against it, but most online examples use SQLAlchemy. Do I still need to use SQLAlchemy if I am not using my own database for Flask?
I am getting errors when the User(Mixin) class is ran.
AttributeError: 'str' object has no attribute 'is_active'
My User class is simple since I do not need have my own DB, just need the 4 methods from the docs.
class User(UserMixin):
pass
Here is some code for trying this just with a dictionary as the DB:
from flask import Flask, url_for, render_template, redirect
from forms import LoginForm
from flask_login import LoginManager, UserMixin, login_required, login_user
users_db = {'user1': 'pass1'}
app = Flask(__name__)
login_manager = LoginManager()
login_manager.init_app(app)
#login_manager.user_loader
def load_user(user_id):
if user_id in users_db:
print('user found in DB')
return user_id
else:
return None
class User(UserMixin):
pass
app.config['SECRET_KEY'] = 'abc123'
#app.route('/', methods=('GET', 'POST'))
def Login():
form = LoginForm()
if form.validate_on_submit():
print('validated')
username = form.username.data
login_user(username)
next = flask.request.args.get('next')
if not is_safe_url(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('hi'))
return render_template('login.html', form=form)
#app.route('/hi')
def hi():
return """<h1>Hi</h1>
{% if current_user.is_authenticated %}
Hi {{ current_user.name }}!
{% endif %}"""
#app.route('/secure')
#login_required
def secure():
return "This is a secure page."
#app.route("/logout")
#login_required
def logout():
logout_user()
return redirect('https://cisco.com')
What would be obviously wrong here, or what could I be conceptually not understanding?
Thanks!!!
Your user_db only contains strings. You have to create an instance of the User class and return the instance on login.
See https://flask-login.readthedocs.io/en/latest/
PS I am on mobile, if this is not enough info, I'll update my answer later.
This article also introduces the login mechanism
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins

'NoneType' object has no attribute 'password'

I want to create a functional login form using flask web framework. I am using Google Datastore. Currently, I am getting the following error.
'NoneType' object has no attribute 'password'
Also, I am not sure about the id attribute I've used in the User Model. May be the server does not recognize id's for each user. Kind of confused. Any help is appreciated.
my models.py file in view:
import datetime
from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import ndb
class User(ndb.Model):
id = ndb.StringProperty()
username = ndb.StringProperty()
email = ndb.StringProperty()
password = ndb.StringProperty()
joined_at = ndb.DateTimeProperty()
updated_at = ndb.DateTimeProperty()
is_admin = ndb.BooleanProperty(default=False)
# Flask-Login integration
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return false
def get_id(self):
return self.id
forms.py file:
class LoginForm(Form):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
main.py:
from flask import Flask, g, flash, render_template, url_for, redirect
from flask_login import LoginManager, login_user
import models
import forms
#app.route('/login', methods=['GET', 'POST'])
def login():
form = forms.LoginForm()
if form.validate_on_submit():
try:
user = models.User.exists(username = form.username.data)
except models.DoesNotExist:
flash("Your email does not match", "error")
else:
if user.password == form.password.data:
login_user(user)
flash("You've been logged in!", "success")
return redirect(url_for('index'))
else:
flash("Your password does not match!", "error")
return render_template('login.html', form=form)
You are currently just checking weather username exists or not. You have to fetch that entity first then check username and password. This will solve your problem.
user_check = User.query(User.username == form.username.data).get()
if user_check:
if user_check.password == form.password.data:
print "Success"
else:
print "Wrong Password"
else:
print "No Username Exists"

Resources