Django custom login issue - python-3.x

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.

Related

Django DeleteView Not Saving Changes

I'm using django DeleteView to delete user account. when i set the user's is_active property to False, it doesn't get saved in the database. it's still set to True
here's my views.py
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.http import HttpResponseRedirect
from django.views.generic.edit import DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
class DeleteAccount(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
"""
DeleteAccount: view to delete user account
"""
model = User
template_name = 'registration/delete_account.html'
success_url = reverse_lazy('core:index')
success_message = 'Account Successfully Deleted!'
def form_valid(self, form):
"""
Delete account and logout current user
"""
account = self.get_object()
# verify if user is the rightful owner of this account
if not account.id == self.request.user.id:
return HttpResponseRedirect(reverse_lazy('accounts:index'))
account.is_active = False # DOESN'T GET SAVED
account.save() # EVEN AFTER CALLING MODEL.SAVE() METHOD
logout(self.request)
return super().form_valid(form)
def get_object(self):
return get_object_or_404(User, pk = self.request.user.id)

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)

User login on Flask?

I've been working through chapters 3 and 4 of the Flask mega-tutorial (https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database). I'm trying to set up user logins on my flask webpage that I have hosted at pythonanywhere. I'm able to register an account successfully (I can see the record added to my database), however, when I try to login, Flask is unable to find the record when searching for the username and it returns None. I'm not sure why this is happening. Complicating things a bit is that I'm using a MySQL database rather than a SQLLite database that the tutorial uses.
config.py:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'something'
SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password#jplank.mysql.pythonanywhere-services.com/jplank$default'
SQLALCHEMY_TRACK_MODIFICATIONS = False
flask_app.py:
from config import Config
from flask_sqlalchemy import SQLAlchemy
from werkzeug.urls import url_parse
from flask import Flask, render_template, flash, redirect, url_for, request
from pandas import DateOffset, DataFrame, date_range, to_datetime
from flask_login import current_user, login_user, logout_user, login_required, LoginManager
import MySQLdb
from flask_bootstrap import Bootstrap
from numpy import nan
from dateutil.relativedelta import relativedelta
import datetime
import math
from yearfrac import CalcYearFrac
import decimal
from sqlalchemy import create_engine
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)
login.login_view = 'login'
Bootstrap(app)
from forms import NameForm, LoginForm, RegistrationForm
import routes, models
#app.route('/table', methods=('GET', 'POST'))
#login_required
def calculatetable():
[...]
models.py:
from flask_app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(UserMixin, db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
routes.py:
from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user
from werkzeug.urls import url_parse
from flask_app import app, db
from forms import LoginForm, RegistrationForm
from models import User
from config import Config
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user =
User.query.filter_by(username=form.username.data).first()
if user is None:
flash('user is none')
flash(form.username.data)
return redirect(url_for('login'))
elif not user.check_password(form.password.data):
flash('not hash match')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('calculatetable')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
#app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
I managed to solve this. There was a problem with the way I'd set up my MySQL table and I didn't have certain columns identified as index. Recreating the table solved the issue.

'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"

Django REST: AttributeError: 'WSGIRequest' object has no attribute 'session'

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.

Resources