Password only auth in Flask - flask

I would like to implement a simple basic password authentication without username in flask.
Different routes should have different passwords:
In #app.route("/project/<string:project_name>", methods=["GET"]) I would like to assign every project with a differing password.
The app is very small and security is not a big concern the solution should therefore also be as simple as possible.

I think this should serve as a solution for you:
pwd = ''
def password_form(project_name):
# The HTML form asking for password
return '''<form method="post">
<label for="pass">Please enter project's password:</label>
<input type="pwd" id="pwd" name="pwd" required>
<input type="submit" value="Sign in">
</form>'''
def check_password(pwd, project_name):
# I set the password to be the reversed name of the project, you can change it
return pwd == project_name[::-1]
#app.route("/project/<string:project_name>", methods=["GET", "POST"])
def project(project_name):
if request.method == "POST":
pwd = request.form['pwd'] # pass the form field name as key
if check_password(pwd, project_name):
return 'success!'
# Return the project's HTML page. If it has a template matching the project's name:
#return render_template(f'{project_name}.html')
else:
# Wrong password, the form will reload
return password_form(project_name)
if request.method == "GET":
return password_form(project_name)

A potential solution.
forms.py
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
project_name = StringField('Project_name', id='project_name')
password = PasswordField('Password',id='password', validators[DataRequired()])
models.py
from flask_login import UserMixin
from sqlalchemy import Binary
from app import db
class Project(db.Model, UserMixin):
__tablename__ = 'Project'
project_name = Column(String, unique=True)
password = Column(Binary)
routes.py
from flask import render_template, redirect, request, url_for
from flask_login import login_user
from app.models import Project
## this could be a simple string comparison **not suggested.
from app.base.util import verify_pass
#app.route('/login', methods=['GET', 'POST'])
def login():
"""
"""
login_form = LoginForm(request.form)
if request.method == 'POST':
# read form data
password = request.form['password']
# project's password given its name.
project = Project.query.filter_by(project_name=project_name).first()
# Verify password.
if project and verify_pass(password, project.password):
# Success.
login_user(user)
return redirect(url_for('app.index'))
# Something (user or pass) is not ok
return render_template( 'login.html',
msg='Wrong password.',
form=login_form
)

Related

Restrict users to access routes in flask

I am trying to create a flask app that will allow users to login, thereafter, they will be redirected to a specific dashboard created and being served with Bokeh.
So, for example, we have an user1, at the beginning he will start in https:myurl/login, after successful login he will be redirected to https:myurl/user1 where his specific dashboard is.
So, my question is, how I can avoid user1 accessing dashboard from other users user2, user3, etc. It is actually possible to do that? I am relatively new to flask, so my apologies if the question sounds silly.
from multiprocessing import connection
from functools import wraps
from re import A
from flask import Flask, render_template, request, flash, redirect, url_for, session
import sqlite3
from sqlalchemy import DATE
# Setup
app = Flask(__name__)
app.secret_key = "my_key"
# Routes
#app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
connection = sqlite3.connect("user_login.db")
cursor = connection.cursor()
# Get what the user has typed in the HTML form
username = request.form["username"]
password = request.form["password"]
# SQL query
cursor.execute(
"SELECT * FROM users WHERE username=? AND password=?", (username, password)
)
data = cursor.fetchone()
if data:
session["username"] = data[1]
session["password"] = data[2]
return redirect(url_for("user({data[1]})"))
# return redirect(f"https://myurl/{session['username']}", code=302)
else:
flash("Username and Password Mismatch", "DANGER! Please try again")
# Render HTML template
return render_template("login.html")
# Check if user is logged in
# def is_logged_in(f):
# #wraps(f)
# def secure_function(*args, **kwargs):
# if "logged_in" in session:
# return f(*args, **kwargs)
# else:
# flash("Unauthorized, please login", "danger")
# return redirect(url_for("login"))
# return secure_function
#app.route("/<username>")
def user(username):
if username == session['username']:
return redirect(
f"https://myurl/{session['username']}", code=302
)
else:
return flash("Unauthorized")
# #app.route('/')
# def logged():
# return redirect(f"https://myurl/{session['username']}", code=302)
if __name__ == "__main__":
app.run(debug=True)
How about verifying if the
current_user.username == myurl/<username>
.username being the name of your user in your Models(if it is name then current_user.name, etc.)
Like
#app.route("/dashboard/<username>")
def dashboard(username):
if username == current_user.username:
#proceed
else:
return "Access Denied"
*** Edit ***
Your provided code for the return statement
redirect(url_for("user({data[1]})"))
Could be written as:
return redirect(url_for('user', username = data[1]))

FileField in flask_wtf.file is not instance of werkzeug.datastructures.FileStorage

I am working on a flask form which has an image upload field, when I submit the form the data attribute of this FileField is set to None. As per the flask documentation.
The FileField provided by Flask-WTF differs from the WTForms-provided
field. It will check that the file is a non-empty instance of
FileStorage, otherwise data will be None.
So I checked in my code for this isinstance(form.profile_picture, FileStorage) and this returns false.
Below are the relevant code snips
Forms.py
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Email, EqualTo, length
from flask_wtf.file import FileField, FileAllowed
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About Me', validators=[DataRequired(),
length(min=10, max=1000)])
profile_picture = FileField('Profile Picture', validators=[FileAllowed([
'jpg', 'png'])])
update = SubmitField('Update')
views.py
#user.route("/edit_profile/", methods=['GET', 'POST'])
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
user = User.query.filter_by(username=current_user.username).first()
user.username = form.username.data
user.about_me = form.about_me.data
# if form.profile_picture.data: # this returns None
# user.profile_pic = process_image(form.profile_picture.data,
# user.username)
print(isinstance(form.profile_picture, FileStorage))
db.session.commit()
return redirect(url_for("user.profile", uname=current_user.username))
elif request.method == 'GET':
form.username.data = current_user.username
form.about_me.data = current_user.about_me
return render_template('user/user_edit_profile.html', form=form)
So am I missing something here ? I have also gone through this question Flask-WTF FileField does not set data attribute to an instance of Werkzeug FileStorage but this was not the issue in my case, as I have not initialized the form with any data.
The solution to this was quite simple, I didn't mentioned the correct encoding type in my form in the template file.
This fixed my problem.
<form method='POST' action='' enctype=multipart/form-data>

Django Updating Existing Model field

I have a model in Django with a foreign key to Django User Model. I am trying to update my model with a form, but database isn't updating. I can't figure out the problem.
model.py
from django.conf import settings
class UserInfo(models.Model):
username = models.CharField(max_length = 30)
owner = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,)
form.py
from django import forms
from society.models import UserInfo
class Editform(forms.ModelForm):
username=forms.CharField(widget=forms.TextInput(attrs={'onchange': 'this.form.submit();', 'class': 'editinput'}))
class Meta:
model = UserInfo
fields ='__all__'
views.py
from django.shortcuts import render
from society.models import UserInfo
from django.contrib.auth.models import User
from society.forms import Editform
def ProfileView(request):
user = request.user
username = UserInfo.objects.get(owner=user)
if request.method == 'POST':
form = Editform(request.POST, instance=username)
if form.is_valid():
form.save()
else:
form = Editform(instance=username)
return render (request, 'profile_view.html', {'user':username, 'form':form})
url.py
from django.conf.urls import url
from django.contrib import admin
import society.views
urlpatterns = [
url(r'^$', 'society.views.home'),
url(r'^admin/', admin.site.urls),
url(r'^login/', 'django.contrib.auth.views.login'),
url(r'^logout/', 'django.contrib.auth.views.logout'),
url(r'^userreg/', 'society.views.UserReg'),
url(r'^profile/', 'society.views.ProfileView'),
]
profile_view.html
<div>
<form method="POST">
{% csrf_token %}
{{form.username}}
{{user.username}}
</form>
</div>
When ever I change form.username, user.username change instantly but the database is not updating. I tried with adding a submit button, but still no luck.
You should pass record id for updating existing UserInfo record.
from django.shortcuts import render
from society.models import UserInfo
from django.contrib.auth.models import User
from society.forms import Editform
def ProfileView(request):
user_id = request.POST.get('user_id')
user = UserInfo.objects.get(pk=user_id)
if request.method == 'POST':
form = Editform(request.POST, instance=user)
if form.is_valid():
form.save()
else:
form = Editform(instance=user)
return render (request, 'profile_view.html', {'user':username, 'form':form})
You can update in 2 method for eg: here i am going to update Your username,
1) if you using object.get():
get_name = UserInfo.objects.get(owner=user)
get_name['username'] = 'Your Input what you need to change'
get_name.save()
2) if you using object.filter():
get_name = UserInfo.objects.filter(owner=user).update(username='your data') # or form.username
Thats it..
Apart from anything else, you haven't pointed your form at anything, so the form can't connect to the logic of the view - in effect, you've specified the form should POST content, but not where to.
The form should point to a URL in your urls.py file, which is of course linked to the view you've shown above. That works in the following way:
<form action="{% url 'core.views.new_comment' %}" method="post">
{% csrf_token %}
...
</form>
There's more guidance about how this works here in the docs. (Obviously people know that the answer's in the docs, the trick is finding it. :) )
(Also, your formatting is off in the views.py, but I think that's just a cut and paste problem when entering the question.)
Anyway I soloved this problem, Thank You everyone. Just Changed the form.py
from django import forms
from society.models import UserInfo
class Editform(forms.ModelForm):
username=forms.CharField(widget=forms.TextInput(attrs={'onchange': 'this.form.submit();', 'class': 'editinput'}))
class Meta:
model = UserInfo
exclude =('owner',)
As owner is a mandatory field, but I omitted it from template it was showing mandatory field error. Its working now. Thanks anyway.

ajax with django forms

can i add the ajax code with django?
i have created a simple registraion form that have 5 fields . i wish to disply the each fields in different pages but in a single window . it means by using next button 5 pages want to disply in a single window. same time all content of each page i want add to my database. is this possible in django with ajax..
my codes are as follows :
#view
from django.shortcuts import render_to_response
from registration.models import UserDetails
from forms import UserForm
from django import forms
from django.template import RequestContext
from django.http import HttpResponseRedirect
def user_details(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
form.save()
else:
form = UserForm()
return render_to_response("career.html", {"form": form},context_instance=RequestContext(request))
#form
from django import forms
from registration.models import UserDetails
class UserForm(forms.ModelForm):
pass
class Meta:
model = UserDetails
#model
from django.db import models
class UserDetails(models.Model):
fname=models.CharField(max_length=20)
lname=models.CharField(max_length=20)
email = models.EmailField()
address = models.CharField(max_length=50)
country = models.CharField(max_length=20)
def __unicode__(self):
return self.fname
return self.lname
return self.email
return self.address
return self.country
#url
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^registration/$', 'registration.views.user_details', name='user_details'),
url(r'^admin/', include(admin.site.urls)),
)
# template
<form enctype="multipart/form-data" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" ....>
</form>
Whay have you tried for ajax call?
Server just serve some result to client then it is up to your client code:
either it is post back that you refresh page
or iframe, you refresh a frame in parent doc
or html tag like tag that you inject by $(targetElement).html($someResultFromServer)
In most case server does not even care what and how it looks like client(rich or thin),
Thats you javascript, query and css codes which to works on behalf of client. Vice versa, in most case client does not even care what is and how it looks like it is server: Loosely coupled
For ajax calls you can follow this link: http://api.jquery.com/jQuery.ajax/
As Martin Thurau stated your question is very hard to understand. Regardless I think that what you are asking for is a stepped form.
Best you take a look at Django's Form Wizard here

forms and ajax in django [duplicate]

can i add the ajax code with django?
i have created a simple registraion form that have 5 fields . i wish to disply the each fields in different pages but in a single window . it means by using next button 5 pages want to disply in a single window. same time all content of each page i want add to my database. is this possible in django with ajax..
my codes are as follows :
#view
from django.shortcuts import render_to_response
from registration.models import UserDetails
from forms import UserForm
from django import forms
from django.template import RequestContext
from django.http import HttpResponseRedirect
def user_details(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
form.save()
else:
form = UserForm()
return render_to_response("career.html", {"form": form},context_instance=RequestContext(request))
#form
from django import forms
from registration.models import UserDetails
class UserForm(forms.ModelForm):
pass
class Meta:
model = UserDetails
#model
from django.db import models
class UserDetails(models.Model):
fname=models.CharField(max_length=20)
lname=models.CharField(max_length=20)
email = models.EmailField()
address = models.CharField(max_length=50)
country = models.CharField(max_length=20)
def __unicode__(self):
return self.fname
return self.lname
return self.email
return self.address
return self.country
#url
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^registration/$', 'registration.views.user_details', name='user_details'),
url(r'^admin/', include(admin.site.urls)),
)
# template
<form enctype="multipart/form-data" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" ....>
</form>
Whay have you tried for ajax call?
Server just serve some result to client then it is up to your client code:
either it is post back that you refresh page
or iframe, you refresh a frame in parent doc
or html tag like tag that you inject by $(targetElement).html($someResultFromServer)
In most case server does not even care what and how it looks like client(rich or thin),
Thats you javascript, query and css codes which to works on behalf of client. Vice versa, in most case client does not even care what is and how it looks like it is server: Loosely coupled
For ajax calls you can follow this link: http://api.jquery.com/jQuery.ajax/
As Martin Thurau stated your question is very hard to understand. Regardless I think that what you are asking for is a stepped form.
Best you take a look at Django's Form Wizard here