I have setup a loopback API, and I plan to use the login as such flask would make requests to loopback and loopback returns an accessToken
For example login to dashboard:
# Login route
#app.route("/login", methods=['GET', 'POST'])
def login():
status = ""
url_login = 'http://localhost:3000/api/Users/login'
try:
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
payload_login = {
"username": str(username),
"password":str(password)
}
print(payload_login)
r = requests.post(url_login, data=payload_login).text
access_token = json.loads(r)
# access_token = r['id']
# access_token = json.loads(access_token)
print("Access Token: " + str(access_token['id']))
return redirect('/') #CHANGE TO 404 PAGE
except Exception as e:
print(e)
return redirect('/') #CHANGE TO 404 PAGE
return render_template('login.html')
#app.route('/dashboard', methods=['GET', 'POST'])
def logged_in_dashboard():
return render_template('index.html')
How do I set it up so that login to dashboard requires accessToken from loopback? In the past I've used app.config['ACCESS_KEY'] ='key' and have set that if it contains a token it would allow the user to login.
But I'm not sure if this is a good practice. Anything you would like to recommend that could handle lots of user logins?
Don't create requests to the API from within the API. To share functionality between endpoints, use functions. You need at least two functions here:
a function returns a token for valid credentials
a function that requires the token being present in the session or in the request Authorization header, for example
Check the approach that chans linked to for more implementation details: How do you implement token authentication in Flask?
Or the official tutorial for how to implement sessions: https://flask.palletsprojects.com/en/1.1.x/quickstart/#sessions
Which has something like this:
#app.route('/')
def index():
# this if is the login requirement
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# Add logic for validating username and password here.
# If credentials are ok, set username to session.
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
Related
I have been trying for some time now to use a login form, create a JWT with Flask-JWT-Extended and then pass it along with a redirect if it passes the checks.
Very simple example below, but I'm getting "No Authorization Header" in return, which makes me think it won't pass the header which is set? I want to protect a view which will render a template if the auth is ok.
#app.route("/")
def index():
return render_template("index.html")
#app.route('/login', methods=['POST'])
def login():
username = request.form["username"]
password = request.form["password"]
if not username:
return jsonify({"msg": "Missing username parameter"}), 400
if not password:
return jsonify({"msg": "Missing password parameter"}), 400
if username != 'test' or password != 'test!':
return jsonify({"msg": "Bad username or password"}), 401
access_token = create_access_token(identity=username)
response = redirect('http://127.0.0.1:5000/protected')
response.headers["Authorization"] = f'Bearer {access_token}'
return response
#app.route('/protected', methods=['GET'])
#jwt_required
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
I'm trying to create a logged area in my Flaks app where each user will have its own routes to access their information.
/user/<userid>/dashboard
/user/<userid>/profile
/user/<userid>/operations
/user/<userid>/analytics
What is the best way to handle that? In the example below, I'm passing the userId variable after the login inside the url_for. Once the redirect will come from the html template don't know how to pass the userId to the other routes.
I was reading something about having multiple routes with a single method but couldn't understand if it fits in what I need. Sry for the noob question and thanks in advance.
#app.route('/logon', methods=['POST'])
def logon():
username = request.form['username']
passwd = request.form['password']
user = login_verified(username, passwd)
session['token'] = user['idToken']
return redirect(url_for('dashboard', usrId=user['userId']))
#app.route('/user/<usrId>/dashboard', methods=['GET'])
def dashboard(usrId):
if 'token' in session:
print('User ID = %s' % usrId)
return render_template('dashboard.html')
else:
return redirect(url_for('login'))
Guys just found a way to do what I was looking for (don't know if this is the best one but works). Below the solution I found:
#app.route('/logon', methods=['POST'])
def logon():
username = request.form['username']
passwd = request.form['password']
user = login_verified(username, passwd)
session['token'] = user['idToken']
return redirect(url_for('dashboard', usrId=user['userId']))
#app.route('/user/<usrId>/dashboard', methods=['GET'])
def dashboard(usrId):
if 'token' in session:
print('User ID = %s' % usrId)
return render_template('dashboard.html', user=usrId)
else:
return redirect(url_for('login'))
#app.route('/user/<usrId>/operations', methods=['GET', 'POST'])
def operations(usrId):
if 'token' in session:
return render_template('operations.html', user=usrId)
else:
return redirect(url_for('login'))
and the template...
<body>
<h1>Dashboard</h1>
<div>
Operações
Perfil
</div>
<br />
<input type="button" value="Logout" onclick="location.href='/logout'" />
</body>
Good day. I'm starting with Flask in Python. Everything goes fine, but I have a problem with the session. The idea is to store the base64 avatar of the user into his session after he logged in. Then, in the layout just access to his avatar by <img src="data:image/png;base64,{{session.user.photo}}" />.
The problem comes when I login, put the base64 into the session and redirect to /home. Inside /home route, I have a simple access control, if the session hasn't user key, redirect to login again. The problem is after set the session and redirect to home, the session is empty in /home, and never render the template.
#root.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
if 'user' in session:
return redirect('/home')
else:
return render_template('login.html', message = None)
else:
username = request.form['username']
pwd = request.form['password']
user = User.where('username', username).where('pwd', pwd).get().first()
if(user == None):
return render_template('login.html', message = 'Usuario o contraseña incorrecta')
else:
session['user'] = {
'id': user.id,
'username': user.username,
'photo': user.photo
}
return redirect('/home')
#root.route('/home')
def home():
if 'user' in session: # THIS IS FALSE, SESSION IS EMPTY
return render_template('home.html')
else:
return redirect(url_for('root.login', message = None))
Flask only accept small data in session? thanks.
I am sorry you shouldn't store a big image in the session.
A good way to achieve it is to store unique image id, and call url with this unique ID. Like this:
<img src = "//myview?id=513654534343543543" />
In short:
By only using the Flask micro-framework (and its dependencies) can we perform an internal redirect from one route to another?
For example:
User submits the registration form (both username and password) to #app.route('/register', methods=['POST'])
If the registration is successful, Flask internally does an HTTP POST to #app.route('/login', methods['POST']) passing the username and password
Process and log in the user
Details:
I am building a REST API using Flask and the Flask-JWT extension. More specifically I'm implementing the login and registration.
Login works perfectly and returns a JSON object with a token.
Following is my (login) authentication handler (i.e. /auth (POST request) - Default Flask-JWT authentication URL rule):
#jwt.authentication_handler
def authenticate(username, password):
user = User.query.filter_by(username=username).first()
if user and user.verify_password(password):
return user
return None
A successful login returns:
{
"token": "<jwt-token>"
}
Following is my registration route:
#app.route('/register', methods=['PUT'])
def register():
username = request.form.get('username')
password = request.form.get('password')
if username is None or password is None:
abort(400) # missing parameters
user = User.query.filter_by(username=username).first()
if user:
abort(400) # user exists
else:
user = User(user=user)
user.hash_password(password)
db.session.add(user)
db.session.commit()
# How do we generate a token?
# Perform an internal redirect to the login route?
return jsonify({'token': <jwt-token>}), 201
You should use the Post-Redirect-Get pattern.
from flask import Flask, redirect, request, render_template
app = Flask("the_flask_module")
#app.route('/', methods=["GET", "POST"])
def post_redirect_get():
if request.method == "GET":
return render_template("post_redirect_get.html")
else:
# Use said data.
return redirect("target", code=303)
#app.route("/target")
def target():
return "I'm the redirected function"
app.run(host="0.0.0.0", port=5001)
And if you want to pass data to the target function (like that token) you can use the session object to store it
So that would break down something like
#app.route('/register', methods=['PUT'])
def register():
username = request.form.get('username')
password = request.form.get('password')
if username is None or password is None:
abort(400) # missing parameters
user = User.query.filter_by(username=username).first()
if user:
abort(400) # user exists
else:
user = User(user=user)
user.hash_password(password)
db.session.add(user)
db.session.commit()
# How do we generate a token?
redirect("login_success", code=307)
#app.route("login_success", methods=["GET", "POST"])
#jwt_required()
def login_success():
return "Redirected Success!"
Edit:
I haven't used Flask-JWT before and didn't know about the post requirement. But you can tell Flask to redirect with the current method used (rather than a get request) by passing the redirect function code=307.. Hopefully that solves your extended problem.
I am generating an auth token with the help of a separate serviceIn login from I am generating authentication token with help of some service. I generate the token in the login route. How can I prevent access to other routes until the login token is generated, and how can I access that token in the other routes?
#app.route('/login', methods=['GET', 'POST'])
def login():
error=None
if request.method=='POST':
if request.form['username']!='admin' or request.form['password']!='1234':
error ='Invalid Credentials. Please try again.'
else:
username=request.form['username']
password=request.form['password']
auth_url='http://192.168.206.133:5000/v2.0'
token = generateToken(username=username, password=password, auth_url=auth_url)
return redirect(url_for('getstats'))
return render_template('login.html', error=error)
# this route should require and use the auth token
#app.route('/metering')
def getstats():
return render_template('metering.html')
So it appears that you are trying to access the token in different routes.
I suggest storing them in a session. To do so, make sure to import the session variable from flask: from flask import session.
You want to set the token's value in the session. Right now, I will use auth_token as the session field, but you can use anything you want:
#app.route('/login', methods=['GET', 'POST'])
def login():
error=None
if request.method=='POST':
if request.form['username']!='admin' or request.form['password']!='1234':
error ='Invalid Credentials. Please try again.'
else:
username=request.form['username']
password=request.form['password']
auth_url='http://192.168.206.133:5000/v2.0'
token = generateToken(username=username, password=password, auth_url=auth_url)
session["auth_token"] = token # store the token in the session here
session["authenticated"] = True
return redirect(url_for('getstats'))
return render_template('login.html', error=error)
from functools import wraps
def authenticated_resource(function):
#wraps(function)
def decorated(*args, **kwargs):
if session.get("authenticated"):
return function(*args, **kwargs)
return redirect(url_for("login"))
return decorated
Then, to access the token:
#app.route('/metering')
#authenticated_resource
def getstats():
token = session.get("auth_token")
# you might want to verify that the token was in the session, as such
if token:
return render_template('metering.html')
else:
abort(403)
Note: to use abort, you also need to import that from flask.