TIL Python Basics Day 68 - Authentication with Flask
16728 ワード
Figure out how to register, login and logout users with email and password. So they can access their own private profile pages.
The send_from_directory function is the recommended secure way to allow a user to download a file from our application.
Docs
Helpful Article
-filename=image_name - The image_name variable passed in from the URL
-as_attachment=True - Allows the client to download the file as an attachment
-send_from_directory is then returned
Why Authenticate?: to associate data with individual users. Access to private contents like messages Restrict Acess depending on user's status: paid membership * Level 1 Encryption: store password into DB.
* Level 2 Authentication: Use of encryption
Scrambling it to be unable to decode data without anigma machine/key
Not using Key
We don’t decrypt the password
Password turned into Hash
Hash doesn’t go backward into original password.
Store hash: When try to login again, send Hash to the DB, DB compare it to stored Hash.
If those two matches, they are same.
In that way, only users know their password.
'Have been pwned?'
Same password -> Same Hash
Generating hashes with GPU
Pre-built hash table: Search by the hash value of common password
Longer the password, harder to crack: Time to crack exponentially increase.
That's why include all Uppercase, Lowercase, Numbers, Symbols over 10 characters.
don’t use dictionary words
* Level 4 : Hashing & Salting
In addition to the password + random set of character (SALT) increases number of character.
Salt it stored in the DB along with Hash
Combine with PW+Salt
We only store Salt and Hash
MD5 is less secure
Industry standard password-hashing function
As computers get faster, almost doubles the computing power.
You can increse the rounds exponentially. It gets securer.
Cookie
-Amazon stores the cookies, session contains id number to be used to fetch all data. If we delete the cookie, we won't be able to see the item in the cart.
-At Amazon, Adding an item in a shopping cart means "Browser POST request to server; I added item to my cart."In response, server creates the cookies containing the data and send it to browser, telling save the coockie in. When browser(user)comeback to the website, browser make GET request, sending along the cookie to server. Server responses by sending html, css, js and cookie.
There are lots of different type of cookies.
Session: a period of time when a browser interacts with a server. When logged in, cookie is created and expires after a certain period of time.
Docs
Flask-Login package provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.
Youtube tutorial by pretty print
-flask login uses user_loader to find whose session is currently active. Flask login will create a cookie when the used is logged in and inside the cookie, will be the 'user id'.
Anytime user performs a request on your app it sends the cookie along with that. Flask looks for the user id and usees user_loader to actually find the user in DB.
-UserMixin adds some attritubes to User class to help Flask_login actually use your User Class.
Check stored password hash against entered password hashed.
#(pw from DB, user typed pw-plain text)
When try to register but user email already on DB, redirect to login
When try to login, find the user by email
function creates the cookcie . session tells flask that user is logged in
-login_required secure the page, only logged in user can view the page.
-current_user object represents user object.
e.g. Secure the/secrets and/download route
Users aren't logged in shouldn't do logout, so login_required
Give user a feedback
e.g. Was there an issue with login in? Are they typing in the wrong password or does their email not exist?
-They are messages that get sent to the template to be rendered just once. And they disappear when the page is reloaded.
When tried to register with existing email at register page, redirects to login and show flash saying Email already esits.(so try loggingin)
main.py
nav bar -> base.html
base.html changes after logging in
Send from directory
The send_from_directory function is the recommended secure way to allow a user to download a file from our application.
Docs
Helpful Article
@app.route("/get-image/<image_name>")
def get_image(image_name):
try:
return send_from_directory(app.config["CLIENT_IMAGES"],
filename=image_name, as_attachment=True)
except FileNotFoundError:
abort(404)
-app.config["CLIENT_IMAGES"] - The path to the directory containing the images we're allowing our users to download-filename=image_name - The image_name variable passed in from the URL
-as_attachment=True - Allows the client to download the file as an attachment
-send_from_directory is then returned
@app.route('/download')
def download():
return send_from_directory('static',
filename='files/cheat_sheet.pdf')
Authentication
Why Authenticate?: to associate data with individual users.
* Level 2 Authentication: Use of encryption
Scrambling it to be unable to decode data without anigma machine/key
Caesar Cipher: early form of encryption
A way of scrambling message
Key to unscramble the msg
* Level 3 Hashing: Password + Key -> Ciphertext
Method
Hash Function
Not using Key
We don’t decrypt the password
Password turned into Hash
Hash doesn’t go backward into original password.
377/1 = 13*29
13*29
Calculated very fast, but doesn’t go backward Store hash: When try to login again, send Hash to the DB, DB compare it to stored Hash.
If those two matches, they are same.
In that way, only users know their password.
How to Hack Password 101
'Have been pwned?'
Same password -> Same Hash
Generating hashes with GPU
Hash Table Cracks
Pre-built hash table: Search by the hash value of common password
Longer the password, harder to crack: Time to crack exponentially increase.
That's why include all Uppercase, Lowercase, Numbers, Symbols over 10 characters.
Dictionary Attack
don’t use dictionary words
Salting Passwords
* Level 4 : Hashing & Salting
In addition to the password + random set of character (SALT) increases number of character.
Salt it stored in the DB along with Hash
Combine with PW+Salt
We only store Salt and Hash
MD5 is less secure
Bcrypt Hashes
Industry standard password-hashing function
Salt Rounds
As computers get faster, almost doubles the computing power.
You can increse the rounds exponentially. It gets securer.
Round 1
PW + SALT => Hash1
(Random set of characters)
Round 2
Hash1 + SALT => Hash2
Round 3
Hash2 + SALT => Hash3
...
DB
User/ Salt/ Hash x 10(rounds)
*level 5: Cookies and SessionsCookie
-Amazon stores the cookies, session contains id number to be used to fetch all data. If we delete the cookie, we won't be able to see the item in the cart.
-At Amazon, Adding an item in a shopping cart means "Browser POST request to server; I added item to my cart."In response, server creates the cookies containing the data and send it to browser, telling save the coockie in. When browser(user)comeback to the website, browser make GET request, sending along the cookie to server. Server responses by sending html, css, js and cookie.
There are lots of different type of cookies.
Session: a period of time when a browser interacts with a server. When logged in, cookie is created and expires after a certain period of time.
1. Hashing Passwords using Werkzeug
generate_password_hash()
hash_and_salted_password = generate_password_hash(
request.form.get('password'),
method='pbkdf2:sha256',
salt_length=8
)
new_user = User(
email=request.form.get('email'),
name=request.form.get('name'),
password=hash_and_salted_password,
)
Security HelpersDocs
2. Authenticating Users with Flask-Login
Flask-Login package provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.
Youtube tutorial by pretty print
1. configure Flask app to use Flask_Login
login_manager = LoginManager()
login_manager.init_app(app)
2. create a user_loader function.
@login_manager.user_loader
def load_user(user_id):
"""to associate the coockie with user object"""
return User.query.get(int(user_id))
-user_loader: How Flask_Login creates the connection btw cookie and data in DB.-flask login uses user_loader to find whose session is currently active. Flask login will create a cookie when the used is logged in and inside the cookie, will be the 'user id'.
Anytime user performs a request on your app it sends the cookie along with that. Flask looks for the user id and usees user_loader to actually find the user in DB.
3. Implement the UserMixin in User class.
from flask_login import UserMixin
class User(UserMixin, db.Model):
-Without UserMinxin, Flask_Login cannot read or modify User class.-UserMixin adds some attritubes to User class to help Flask_login actually use your User Class.
4. check_password_hash function.
Check stored password hash against entered password hashed.
#(pw from DB, user typed pw-plain text)
#1 check only password
password = request.form.get('password')
if check_password_hash(user.password, password):
login_user(user)
#2 check both email in DB and password
email = request.form.get('email')
password = request.form.get('password')
user = User.query.filter_by(email=email).first()
if not user and not check_password_hash(user.password, password):
return redirect(url_for("login"))
login_user(user)
5. Find the user by the email
When try to register but user email already on DB, redirect to login
When try to login, find the user by email
email = request.form.get('email')
user = User.query.filter_by(email=email).first()
6. login_user(user) function to authenticate them.
function creates the cookcie . session tells flask that user is logged in
7. Login_required
-login_required secure the page, only logged in user can view the page.
-current_user object represents user object.
e.g. Secure the/secrets and/download route
@app.route('/secrets')
@login_required
def secrets():
return render_template("secrets.html", name=current_user.name)
secrets.html <h1 class="title">Welcome, {{ name }} </h1>
8. Log out
Users aren't logged in shouldn't do logout, so login_required
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index.html'))
Flask Flash messages
Give user a feedback
e.g. Was there an issue with login in? Are they typing in the wrong password or does their email not exist?
-They are messages that get sent to the template to be rendered just once. And they disappear when the page is reloaded.
When tried to register with existing email at register page, redirects to login and show flash saying Email already esits.(so try loggingin)
main.py
if user:
flash("Email address already exists. ")
return redirect(url_for('login'))
login.html <h1>Login</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
Passing Authentication Status to Templates
nav bar -> base.html
{% if not current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('home') }}">Home</a>
</li>
{% if not current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register') }}">Register</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Log Out</a>
</li>
base.html changes after logging in
Reference
この問題について(TIL Python Basics Day 68 - Authentication with Flask), 我々は、より多くの情報をここで見つけました https://velog.io/@daylee/TIL-Python-Basics-Day-68-Authentication-with-Flaskテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol