├── Pipfile ├── Pipfile.lock └── project ├── __init__.py ├── auth.py ├── db.sqlite ├── main.py ├── models.py └── templates ├── base.html ├── index.html ├── login.html ├── profile.html └── signup.html /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | flask = "*" 8 | 9 | [dev-packages] 10 | 11 | [requires] 12 | python_version = "3.7" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "a82b674d67d29678775ff6b773de1686a9593749ec14483b0d8e05131b662286" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "click": { 20 | "hashes": [ 21 | "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", 22 | "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" 23 | ], 24 | "version": "==7.0" 25 | }, 26 | "flask": { 27 | "hashes": [ 28 | "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", 29 | "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" 30 | ], 31 | "index": "pypi", 32 | "version": "==1.0.2" 33 | }, 34 | "itsdangerous": { 35 | "hashes": [ 36 | "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", 37 | "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" 38 | ], 39 | "version": "==1.1.0" 40 | }, 41 | "jinja2": { 42 | "hashes": [ 43 | "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", 44 | "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" 45 | ], 46 | "version": "==2.10" 47 | }, 48 | "markupsafe": { 49 | "hashes": [ 50 | "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", 51 | "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", 52 | "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", 53 | "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", 54 | "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", 55 | "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", 56 | "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", 57 | "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", 58 | "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", 59 | "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", 60 | "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", 61 | "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", 62 | "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", 63 | "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", 64 | "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", 65 | "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", 66 | "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", 67 | "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", 68 | "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", 69 | "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", 70 | "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", 71 | "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", 72 | "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", 73 | "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", 74 | "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", 75 | "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", 76 | "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", 77 | "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" 78 | ], 79 | "version": "==1.1.0" 80 | }, 81 | "werkzeug": { 82 | "hashes": [ 83 | "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", 84 | "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" 85 | ], 86 | "version": "==0.14.1" 87 | } 88 | }, 89 | "develop": {} 90 | } 91 | -------------------------------------------------------------------------------- /project/__init__.py: -------------------------------------------------------------------------------- 1 | # init.py 2 | 3 | from flask import Flask 4 | from flask_sqlalchemy import SQLAlchemy 5 | from flask_login import LoginManager 6 | 7 | # init SQLAlchemy so we can use it later in our models 8 | db = SQLAlchemy() 9 | 10 | def create_app(): 11 | app = Flask(__name__) 12 | 13 | app.config['SECRET_KEY'] = '9OLWxND4o83j4K4iuopO' 14 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite' 15 | 16 | db.init_app(app) 17 | 18 | login_manager = LoginManager() 19 | login_manager.login_view = 'auth.login' 20 | login_manager.init_app(app) 21 | 22 | from .models import User 23 | 24 | @login_manager.user_loader 25 | def load_user(user_id): 26 | # since the user_id is just the primary key of our user table, use it in the query for the user 27 | return User.query.get(int(user_id)) 28 | 29 | # blueprint for auth routes in our app 30 | from .auth import auth as auth_blueprint 31 | app.register_blueprint(auth_blueprint) 32 | 33 | # blueprint for non-auth parts of app 34 | from .main import main as main_blueprint 35 | app.register_blueprint(main_blueprint) 36 | 37 | return app -------------------------------------------------------------------------------- /project/auth.py: -------------------------------------------------------------------------------- 1 | # auth.py 2 | 3 | from flask import Blueprint, render_template, redirect, url_for, request, flash 4 | from werkzeug.security import generate_password_hash, check_password_hash 5 | from flask_login import login_user, logout_user, login_required 6 | from .models import User 7 | from . import db 8 | 9 | auth = Blueprint('auth', __name__) 10 | 11 | @auth.route('/login') 12 | def login(): 13 | return render_template('login.html') 14 | 15 | @auth.route('/login', methods=['POST']) 16 | def login_post(): 17 | email = request.form.get('email') 18 | password = request.form.get('password') 19 | remember = True if request.form.get('remember') else False 20 | 21 | user = User.query.filter_by(email=email).first() 22 | 23 | # check if user actually exists 24 | # take the user supplied password, hash it, and compare it to the hashed password in database 25 | if not user or not check_password_hash(user.password, password): 26 | flash('Please check your login details and try again.') 27 | return redirect(url_for('auth.login')) # if user doesn't exist or password is wrong, reload the page 28 | 29 | # if the above check passes, then we know the user has the right credentials 30 | login_user(user, remember=remember) 31 | return redirect(url_for('main.profile')) 32 | 33 | @auth.route('/signup') 34 | def signup(): 35 | return render_template('signup.html') 36 | 37 | @auth.route('/signup', methods=['POST']) 38 | def signup_post(): 39 | 40 | email = request.form.get('email') 41 | name = request.form.get('name') 42 | password = request.form.get('password') 43 | 44 | user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database 45 | 46 | if user: # if a user is found, we want to redirect back to signup page so user can try again 47 | flash('Email address already exists') 48 | return redirect(url_for('auth.signup')) 49 | 50 | # create new user with the form data. Hash the password so plaintext version isn't saved. 51 | new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256')) 52 | 53 | # add the new user to the database 54 | db.session.add(new_user) 55 | db.session.commit() 56 | 57 | return redirect(url_for('auth.login')) 58 | 59 | @auth.route('/logout') 60 | @login_required 61 | def logout(): 62 | logout_user() 63 | return redirect(url_for('main.index')) -------------------------------------------------------------------------------- /project/db.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PrettyPrinted/flask_auth_scotch/2e4094565d0f841ea6e53f51405a9ed8663ab5e7/project/db.sqlite -------------------------------------------------------------------------------- /project/main.py: -------------------------------------------------------------------------------- 1 | # main.py 2 | 3 | from flask import Blueprint, render_template 4 | from flask_login import login_required, current_user 5 | 6 | main = Blueprint('main', __name__) 7 | 8 | @main.route('/') 9 | def index(): 10 | return render_template('index.html') 11 | 12 | @main.route('/profile') 13 | @login_required 14 | def profile(): 15 | return render_template('profile.html', name=current_user.name) -------------------------------------------------------------------------------- /project/models.py: -------------------------------------------------------------------------------- 1 | # models.py 2 | 3 | from flask_login import UserMixin 4 | from . import db 5 | 6 | class User(UserMixin, db.Model): 7 | id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy 8 | email = db.Column(db.String(100), unique=True) 9 | password = db.Column(db.String(100)) 10 | name = db.Column(db.String(1000)) -------------------------------------------------------------------------------- /project/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Flask Auth Example 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 48 |
49 | 50 |
51 |
52 | {% block content %} 53 | {% endblock %} 54 |
55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /project/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends "base.html" %} 4 | 5 | {% block content %} 6 |

7 | Flask Login Example 8 |

9 |

10 | Easy authentication and authorization in Flask. 11 |

12 | {% endblock %} -------------------------------------------------------------------------------- /project/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends "base.html" %} 4 | 5 | {% block content %} 6 |
7 |

Login

8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 |
12 | {{ messages[0] }} 13 |
14 | {% endif %} 15 | {% endwith %} 16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 |
29 | 33 |
34 | 35 |
36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /project/templates/profile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends "base.html" %} 4 | 5 | {% block content %} 6 |

7 | Welcome, {{ name }}! 8 |

9 | {% endblock %} -------------------------------------------------------------------------------- /project/templates/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends "base.html" %} 4 | 5 | {% block content %} 6 |
7 |

Sign Up

8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 |
12 | {{ messages[0] }}. Go to login page. 13 |
14 | {% endif %} 15 | {% endwith %} 16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 | 36 |
37 |
38 |
39 | {% endblock %} --------------------------------------------------------------------------------