i´m doing a simple project where I want to add jwt authentication.
When I log in I try to create a new token but when i´m trying to see who´s the user using the token it says that the token is missing.
I´m using Flask and SQLAlchemy with Postgresql
app.py
app.config['JWT_TOKEN_LOCATION'] = ['cookies']
#app.config['JWT_COOKIE_SECURE'] = False
app.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
app.config['JWT_REFRESH_COOKIE_PATH'] = '/token/refresh'
app.config['JWT_COOKIE_CSRF_PROTECT'] = False
app.config['JWT_SECRET_KEY'] = 'abva'
jwt = JWTManager(app)
#app.route('/token/auth', methods=['POST'])
def login():
email = request.form['email']
password = request.form['password']
user = User.query.all()
for user in user:
if user.email == email and user.password == password:
access_token = create_access_token(identity=user.email)
refresh_token = create_refresh_token(identity=user.email)
# Set the JWTs and the CSRF double submit protection cookies
# in this response
resp = jsonify({'login': True})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
return jsonify({'login': False}), 401
#app.route('/protected', methods=['GET'])
#jwt_required
def protected():
ret = {
'current_identity': get_jwt_identity(), # test
}
return jsonify(ret), 200
#app.route('/token/remove', methods=['POST'])
def logout():
resp = jsonify({'logout': True})
unset_jwt_cookies(resp)
return resp, 200
#jwt.user_identity_loader
def user_identity_lookup(user):
return user
add_user.html
<!DOCTYPE html>
<html>
<body>
<form method="POST" action="/token/auth">
<label> Email: </label>
<input id="email" name ="email" type="text" />
<label> Password: </label>
<input id="password" name ="password" type="password" />
<input type="submit" />
</form>
<form method="POST" action="/token/remove">
<input type="submit" value="LogOut" />
</form>
</body>
</html>
Your route is /protected but your JWT_ACCESS_COOKIE_PATH is /api/. That will prevent the cookie from being sent to that endpoint. Either change the endpoint to /api/protected, or change the cookie path to just /
Related
I can't make my code work. I've been looking around for tutorials and guides but to no avail. If anyone see the mistake I'm doing, it would be very helpful.
Here is the folder structure:
/
application.py
database.db
/routes
__init__.py
signup.py
/templates
signup.html
Here is my signup.py:
import sqlite3
from flask import Blueprint, render_template, redirect, session, request, flash
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
# Set Blueprints
signup = Blueprint('signup', __name__,)
#signup.route("/signup", methods=["GET", "POST"])
def signupFunction():
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
try:
email = request.form.get("email")
username = request.form.get("username")
password = request.form.get("password")
confirmPassword = request.form.get("confirm-password")
with sqlite3.connect("./database") as connection:
print("Opened database successfully")
current = connection.cursor()
# Ensure email was submitted
if not email:
return flash("must provide email")
# Ensure username was submitted
if not username:
return flash("must provide username")
# Ensure password was submitted
if not password:
return flash("must provide password")
# Ensure confirm password is correct
if password != confirmPassword:
return flash("The passwords don't match")
# Query database for username if already exists
current.execute("SELECT * FROM users WHERE username = :username", username=username)
if current.fetchall() == username:
return flash("Username already taken")
# Insert user and hash of the password into the table
current.execute("INSERT INTO users(username, hash) VALUES (:username, :hash)", username=username, hash=generate_password_hash(password))
current.commit()
# Query database for username
current.execute("SELECT * FROM users WHERE username = :username", username=username)
rows = current.fetchall()
# Remember which user has logged in
session["user_id"] = rows[0]["id"]
# Commit to databse
connection.commit()
print("Database operation succesful")
except:
connection.rollback()
print("Error in sign up operation")
finally:
# Close database connection
connection.close()
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("signup.html")
here is my signup.html
{% extends "layout.html" %}
{% block title %}
Sign Up
{% endblock %}
{% block main %}
<p>Register or <a href='/signin'>login</a></p><br>
<form action="/signup" method="post">
<div>
<p>Username (6 characters min).</p>
<input id="username" autocomplete="off" autofocus class="form-control" name="username" placeholder="Username" type="text">
</div>
<br>
<div>
<p>Email.</p>
<input id="email" autocomplete="off" autofocus class="form-control" name="email" placeholder="Email" type="text">
</div>
<br>
<div>
<p>Password (7 to 15 characters, 1 numeric, 1 special).</p>
<input id="password" name="password" placeholder="Password" type="password">
</div>
<div>
<input id="confirm-pass" name="confirm-password" placeholder="Confirm Password" type="password">
</div>
<br>
<button id="submit" type="submit">Sign Up</button>
<br>
</form>
<script>
// Password must be between 7 to 15 characters which contain at least one numeric digit and a special character
document.querySelector("#submit").disabled = true;
document.querySelector("#confirm-pass").onkeyup = function() {
let password = document.querySelector("#password").value;
let username = document.querySelector("#username").value;
let email = document.querySelector("#email").value;
let confirmation = document.querySelector("#confirm-pass").value;
if (password.match(/^^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{7,15}$/i)) {
document.querySelector("#submit").disabled = true;
if (email.match(/^(([^<>()\[\]\.,;:\s#\"]+(\.[^<>()\[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()[\]\.,;:\s#\"]+\.)+[^<>()[\]\.,;:\s#\"]{2,})$/i)) {
document.querySelector("#submit").disabled = true;
if (username.length > 5) {
document.querySelector("#submit").disabled = true;
if (confirmation === password) {
document.querySelector("#submit").disabled = false;
}
}
}
}
else {
document.querySelector('#submit').disabled = true;
}
}
</script>
{% endblock %}
Here is the output of my console:
* Serving Flask app "application.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /signup HTTP/1.1" 200 -
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /static/styles.css HTTP/1.1" 200 -
Opened database successfully
Error in sign up operation
So the problem lies in signup.py
The try/except block is not doing you any favors. It can error on any line and all you'll know is "Error in signup operation". There will be problems because of invalid execute syntax. execute takes at most 2 arguments, the first is the sql to be executed. If it contains placeholders, the second argument is a set. Since these sqls are using named style, the second argument should be a dictionary, as per this example from the doc.
# And this is the named style:
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})
You might consider "catching" the exception and adding more info to the message, something like:
except Exception as e:
print("Error in sign up operation: ",e)
I am trying to build a budgeting webapp, mostly for practice, but I'd also like this to become my primary budgeting tool. I'm not great at Python, but I want to be.
I'm having a tough time of it, which is why I'm turning to you guys.
Here's my code for budget.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['POST', 'GET'])
def entry():
return render_template('entry.html',
the_title='Smith Family Budgeting')
#app.route('/income', methods=['POST', 'GET'])
def income():
return render_template('income.html')
#app.route('/housing', methods=['POST', 'GET'])
def results():
if request.method == 'POST':
income = request.form["income"]
return render_template('housing.html', the_income = income)
#app.route('/transportation', methods=['POST', 'GET'])
def transport():
if request.method == 'POST':
income = request.form["income"]
mortgage = request.form['housing']
leftover = int(income) - int(mortgage)
return render_template('trans.html', leftover=leftover)
app.run(debug = True)
html for housing.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Allocating for housing</title>
</head>
<body>
<p>You have ${{ the_income }} left to spend!</p>
<form action="/transportation">
<p>How much is the mortgage this month?</p>
<input name="housing" type="TEXT">
<p>Next up: Transportation</p>
<input type="SUBMIT" value="Next">
</form>
<form action="/income">
<input type="SUBMIT" value="Back">
</form>
</body>
</html>
As you can probably see from looking, the user progresses through the app by entering data for each category. I'd like to keep a running count of remaining budget, but I'm struggling to get past the first part.
When flask calls the /transportation page, I get "TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement."
I'm not sure why this would be, although I suspect it has to do with the "leftover" variable. I suspect perhaps subtracting the values of two different form data isn't the right way to go about this, but I'm not sure what is. Any advice is welcome!
I can post the templates, although I'm not sure they're needed to solve this one. Thanks so much guys, I'm really glad this resource exists.
Use session to pass data to next route and clear session when user goes back to income page
Use url_for for form action
In budget.py
from flask import Flask, render_template, request, session
app = Flask(__name__)
app.secret_key = "super_secret_key"
#app.route('/', methods=['GET'])
def entry():
return render_template('entry.html',
the_title='Smith Family Budgeting')
#app.route('/income', methods=['GET'])
def income():
session['income'] = ''
return render_template('income.html')
#app.route('/housing', methods=['POST'])
def results():
if request.method == 'POST':
session['income'] = request.form["income"]
return render_template('housing.html', the_income=session['income'])
#app.route('/transportation', methods=['POST'])
def transport():
if request.method == 'POST':
income = session["income"]
mortgage = request.form['housing']
leftover = int(income) - int(mortgage)
return render_template('trans.html', leftover=leftover)
app.run(debug = True)
In housing.html edit form action and method
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Allocating for housing</title>
</head>
<body>
<p>You have ${{ the_income }} left to spend!</p>
<form action="{{ url_for('transport') }}" method="POST">
<p>How much is the mortgage this month?</p>
<input name="housing" type="TEXT">
<p>Next up: Transportation</p>
<input type="SUBMIT" value="Next">
</form>
<form action="{{ url_for('income') }}">
<input type="SUBMIT" value="Back">
</form>
</body>
</html>
I am inserting the data in database using Flask SQLAlchemy
Everything is going fine when I insert data using "/" in action attribute code but when I use to redirect to action="users.html" page after posting the data
I get the message "the method is not allowed for requested url in users page and data does not save too"
<form method="POST" action="/">
Name <input type="text" name="name">
<br>
Password <input type="text" name="email">
<br>
<input type="submit">
</form>
class Users(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
#app.route("/", methods = ['GET', 'POST'])
def contact():
if(request.method=='POST'):
'''Add entry to the database'''
name = request.form.get('name')
email = request.form.get('email')
entry = Users(name=name, email=email)
db.session.add(entry)
db.session.commit()
return render_template('index.html')
#app.route('/users')
def users():
return render_template('users.html')
Try adding methods=['POST'] to:
#app.route('/users', methods=['POST'])
def users():
return render_template('users.html')
At the moment I am just trying to get the function to print what it has found in
the database, however I am not getting anything in the CLI when submitting
eywords via a form which has this functions URL as an action.
import os
from flask import Flask, render_template, redirect, request, url_for
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
app = Flask(__name__)
app.config["MONGO_DBNAME"] = 'recipe_site'
app.config["MONGO_URI"] = os.getenv("MONGO_URI")
mongo = PyMongo(app)
#function for search bar.
#app.route('/search', methods=['GET', 'POST'])
def search():
mongo.db.recipes.create_index( { "name": "text" } )
if request.method == "POST":
q = request.form['search']
else:
q = ""
query = ( { "$text": { "$search": q } } )
results = mongo.db.recipes.find(query)
return render_template('searchresults.html', recipes = results)
The form that calls search function and captures key search word:
<form action="{{ url_for('search', text=text) }}" method="POST">
<div>
<div class="input-field">
<input id="search" name="search" type="text" class="validate">
<span class="helper-text" data-error="Try again" data-success="Done"></span>
</div>
</div>
<button type="submit">Submit </button>
</form>
Error code
Debugger PIN: 272-267-243
10.240.1.220 - - [25/May/2019 19:24:14] "POST /search/ HTTP/1.1" 404 -
As the code stands now all I expect is that it should print any collections in my database which have the keyword searched using the form.
You need to read the key words received from the post request using request.form['search']
like below:
#function for search bar.
#app.route('/search', methods=['GET', 'POST'])
def search():
# index for field name
mongo.db.recipes.create_index('name')
# index for field name and example
#mongo.db.recipes.create_index([("name", pymongo.DESCENDING),
#("example", pymongo.ASCENDING)])
if request.method == "POST":
q=request.form['search']
else:
q = ""
query = ( { "$text": { "$search": q } } )
results = mongo.db.recipes.find(query)
print (results)
return render_template('searchresults.html', recipes = results)
In the form, you need to replace
<form action="{{ url_for('search', text=text) }}" method="POST">
By
<form action="{{ url_for('search') }}" method="POST">
Edit:
I suggest to use GET method instead of POST for search feature because when the client refresh the browser, it ask him to confirm Form submission. So we need to replace:
if request.method == "POST":
q=request.form['search']
else:
q = ""
By
q = request.args.get('search', "")
And
<form action="{{ url_for('search') }}" method="POST">
by
<form action="{{ url_for('search') }}" method="GET">
Using the official documentation for PyMongo
Here is a tested code that might help.
from flask import Flask
from flask_pymongo import PyMongo
import pymongo
app = Flask(__name__)
app.config["MONGO_DBNAME"] = 'test'
app.config["MONGO_URI"] = "mongodb+srv://<username>:<password>#cluster0-vhd1j.gcp.mongodb.net/test?retryWrites=true"
mongo = PyMongo(app)
# mongo.db.collection.create_index([("name", pymongo.ASCENDING),("text", pymongo.ASCENDING)])
mongo.db.collection.insert_one({"name":"myname","text":"abcd"})
query = { "text": "abcd"}
results = mongo.db.collection.find(query)
for result in results:
print(result)
you can manipulate it as per your requirement. :)
I hope it helps.
Thank you for your attempts to support but I have now rectified the issue. The reason why nothing was printing in the cli was due the there being an issue with the create_index line. There was an existing index within that collection i was unaware of which was preventing this line from running.
I am trying to set up login page before accessing any other page. So as of now the code is working fine but if I access '/home' its taking directly to that page without login required page.
I tried to understand online solutions like login-required with SQLAlchemy but nothing seems working and I got totally lost. This does not require login-required I guess.
Here's my code:
from dbscriptdeploy import dbupdate
from flask.templating import render_template
from flask import Flask, request, url_for, redirect
DBupdate = dbupdate()
app = Flask(__name__) #create the Flask app
#app.route('/success')
def deploy_success():
return render_template("success.html")
def deploy_script(sql):
res = DBupdate.dbvalues_get(sql)
return res
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
return redirect(url_for('form_example'))
return render_template('login.html', error=error)
#app.route('/home', methods=['GET', 'POST'])
def form_example():
res = None
error = ''
try:
if request.method == 'POST':
sql = request.form.get('sql')
res = deploy_script(sql)
if res:
return redirect(url_for('deploy_success'))
else:
error = "*Invalid Value. Please try again."
return render_template('home.html', error=error)
except Exception as e:
return render_template('home.html', error=error)
if __name__ == '__main__':
app.run(debug=True) #run app in debug mode on port 5000
Login.html Code:
<html>
<head>
<title>Flask Intro - login page</title>
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="Username" name="username" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">
<input class="btn btn-default" type="submit" value="Login">
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>
So what I expect is after successful login only then they should be directed to \home page else they should be directed again to login page.
If I were you, I'd use flask-login. However, if you want to develop a simple solution by your own, you should save some var in the user's session.
Also in your login method there is a bug. I'd do:
from flask import session
#app.route('/', methods=['GET', 'POST'])
def login_page():
error = None
if request.method == 'POST':
if request.form['username'] == 'admin' and request.form['password'] == 'admin':
session['admin'] = request.form['username']
return redirect(url_for('form_example'))
else:
error = 'Invalid Credentials. Please try again.'
return render_template('login.html', error=error)
Then, in your form_example view you should check that admin is in session, else you can redirect to your login view:
#app.route('/home', methods=['GET', 'POST'])
def form_example():
if 'admin' not in session:
return redirect(url_for('login_page'))
else:
# Your code here
If you really want to go down the path of developing your own login/authentication solution, check out the documentation for flash_message
http://flask.pocoo.org/docs/1.0/patterns/flashing/. This tutorial has the exact problem you're tackling.
The re-routing of a successful login attempt occurs with the redirect call
return redirect(url_for('homepage'))