Flask User Authentication – How to Setup User Login in Flask? – AskPython

Introduction

JSON Web Tokens (or JWTs) provide a means of transmitting information from the client to the server in a stateless, secure way.

1 Setup a Password Hash

The solution is to use a Password Hash. Let us see what a hash is, so go to the python shell in the terminal and run the command

We will get a long random string as shown below:

Hence even if the hacker gets access to them, he won’t be able to decrypt. Also, we have another function to compare the Hash with a password, called check_password_hash.

It works as below:

Now hit enter, it will return True if matched and False if unmatched.

2 Adding Hashed Passwords to Your Database

Also if you don’t have FlaskSQLAlchemy, simply install it using the pip command:

Okay, now that SQLAlchemy is in place, create a file models.py and add the code:

Here:

3. Setting the Flask_login Extension

Also, we need to create and initialize the Flask_login extension. We do it using the code:

4. Complete Code

That’s it with the models.py part. Let us just look at the whole code once:

Do check out our SQLAlchemy Article if you are unfamiliar with Flask SQLAlchemy.

Coding our main Flask application file

Now let’s code our main Flask Application File.

1 Linking Database to our Flask File

Okay now we need to link our SQLite database with SQLALchemy. So for that add the code:

Just replace <db_name> with whatever name you want. Also, we need to link our SQLAlchemy DB instance (present in models.py file) with the main app. For that, add:

3 Coding a Simple View

Hence add a simple view:

Note how we have used the @login_required decorator. The blog.html template would be:

Do checkout our Flask Templates article to know more about Templates.

Basic application structure

For this application, we’ll have a virtual environment in its own directory, as well as a folder containing the main application files. Here’s an overview of the app’s structure:

.├── auth-app│   ├── app.py │   ├── database.db │   ├── forms.py │   ├── manage.py │   ├── migrations│   ├── models.py │   ├── requirements.txt │   ├── routes.py │   ├── run│   ├── static│   └── templates│       ├── auth.html │       ├── base.html │       └── index.html └── venv

Code smell

Finally, take a look at test_auth.py. Notice the duplicate code? For example:

There are eight occurrences of this. To fix, add the following helper at the top of the file:

Configuring for flask-login

I wouldn’t be a gentleman unless I revealed my config.py file. Again, this should all be straightforward if you’ve been following the rest of our series:

Creating log-in and sign-up forms

Hopefully you’ve become somewhat acquainted with Flask-WTF or WTForms in the past. We create two form classes in forms.py which cover our most essential needs: a sign-up form, and a log-in form:

Creating our login routes

Let’s get things started by setting up a Blueprint for our authentication-related routes:

Database setup

Let’s set up Postgres.

NOTE: If you’re on a Mac, check out Postgres app.

Once the local Postgres server is running, create two new databases from psql that share the same name as your project name:

NOTE: There may be some variation on the above commands, for creating a database, based upon your version of Postgres. Check for the correct command in the Postgres documentation.

Before applying the database migrations we need to update the config file found in project/server/config.py. Simply update the database_name:

Set the environment variables in the terminal:

Update the following tests in project/tests/test__config.py:

Run them to ensure they still pass:

You should see:

Forms.py

a). Registration form

Getting started

Enough theory, let’s start implementing some code!

Project setup

Start by cloning the project boilerplate and then create a new branch:

Create and activate a virtualenv and install the dependencies:

This is optional, but it’s a good idea to create a new Github repository and update the remote:

Database setup

Let’s set up Postgres.

NOTE: If you’re on a Mac, check out Postgres app.

Once the local Postgres server is running, create two new databases from psql that share the same name as your project name:

NOTE: There may be some variation on the above commands, for creating a database, based upon your version of Postgres. Check for the correct command in the Postgres documentation.

Before applying the database migrations we need to update the config file found in project/server/config.py. Simply update the database_name:

Set the environment variables in the terminal:

Update the following tests in project/tests/test__config.py:

Run them to ensure they still pass:

You should see:

Important: login helpers

Before your app can work like the above, we need to finish auth.py by providing a couple more routes:

Jwt setup

The auth workflow works as follows:

This cycle repeats until the token expires or is revoked. In the latter case, the server issues a new token.

The tokens themselves are divided into three parts:

We’ll dive a bit deeper into the payload, but if you’re curious, you can read more about each part from the Introduction to JSON Web Tokens article.

To work with JSON Web Tokens in our app, install the PyJWT package:

Logout route tests

Tests valid logout:

deftest_valid_logout(self):""" Test for logout before token expires """withself.client:# user registrationresp_register=self.client.post('/auth/register',data=json.dumps(dict(email='[email protected]',password='123456')),content_type='application/json',)data_register=json.loads(resp_register.data.decode())self.assertTrue(data_register['status']=='success')self.assertTrue(data_register['message']=='Successfully registered.')self.assertTrue(data_register['auth_token'])self.assertTrue(resp_register.content_type=='application/json')self.assertEqual(resp_register.status_code,201)# user loginresp_login=self.client.post('/auth/login',data=json.dumps(dict(email='[email protected]',password='123456')),content_type='application/json')data_login=json.loads(resp_login.data.decode())self.assertTrue(data_login['status']=='success')self.assertTrue(data_login['message']=='Successfully logged in.')self.assertTrue(data_login['auth_token'])self.assertTrue(resp_login.content_type=='application/json')self.assertEqual(resp_login.status_code,200)# valid token logoutresponse=self.client.post('/auth/logout',headers=dict(Authorization='Bearer ' json.loads(resp_login.data.decode())['auth_token']))data=json.loads(response.data.decode())self.assertTrue(data['status']=='success')self.assertTrue(data['message']=='Successfully logged out.')self.assertEqual(response.status_code,200)

Migrations

Add a models.py file to the “server” directory:

# project/server/models.pyimportdatetimefromproject.serverimportapp,db,bcryptclassUser(db.Model):""" User Model for storing user related details """__tablename__="users"id=db.Column(db.Integer,primary_key=True,autoincrement=True)email=db.Column(db.String(255),unique=True,nullable=False)password=db.Column(db.String(255),nullable=False)registered_on=db.Column(db.DateTime,nullable=False)admin=db.Column(db.Boolean,nullable=False,default=False)def__init__(self,email,password,admin=False):self.email=emailself.password=bcrypt.generate_password_hash(password,app.config.get('BCRYPT_LOG_ROUNDS')).decode()self.registered_on=datetime.datetime.now()self.admin=admin

Objectives

By the end of this tutorial, you will be able to…

Project setup

Start by cloning the project boilerplate and then create a new branch:

Create and activate a virtualenv and install the dependencies:

This is optional, but it’s a good idea to create a new Github repository and update the remote:

Refactor

For the PyBites Challenge, let’s refactor some code to correct an issue added to the GitHub repo. Start by adding the following test to test_auth.py:

Register route

Start with a test:

Make sure to add the import:

Run the tests. You should see the following error:

Now, let’s write the code to get the test to pass. Add the following to project/server/auth/views.py:

classRegisterAPI(MethodView):"""    User Registration Resource    """defpost(self):# get the post datapost_data=request.get_json()# check if user already existsuser=User.query.filter_by(email=post_data.get('email')).first()ifnotuser:try:user=User(email=post_data.get('email'),password=post_data.get('password'))# insert the userdb.session.add(user)db.session.commit()# generate the auth tokenauth_token=user.encode_auth_token(user.id)responseObject={'status':'success','message':'Successfully registered.','auth_token':auth_token.decode()}returnmake_response(jsonify(responseObject)),201exceptExceptionase:responseObject={'status':'fail','message':'Some error occurred. Please try again.'}returnmake_response(jsonify(responseObject)),401else:responseObject={'status':'fail','message':'User already exists. Please Log in.',}returnmake_response(jsonify(responseObject)),202# define the API resourcesregistration_view=RegisterAPI.as_view('register_api')# add Rules for API Endpointsauth_blueprint.add_url_rule('/auth/register',view_func=registration_view,methods=['POST'])

Sanity check

Did it work?

There you have it

If you’ve made it this far, I commend you for your courage. To reward your accomplishments, I’ve published the source code for this tutorial on Github for your reference. Godspeed, brave adventurer.

Conclusion

In this tutorial, we went through the process of adding authentication to a Flask app with JSON Web Tokens. Turn back to the objectives from the beginning of this tutorial. Can you put each one into action? What did you learn?

What’s next? How about the client-side. Check out Token-Based Authentication With Angular for adding Angular into the mix.

To see how to build a complete web app from scratch using Flask, check out our video series:

Free Bonus:Click here to get access to a free Flask Python video tutorial that shows you how to build Flask web app, step-by-step.

Feel free to share your comments, questions, or tips in the comments below. The full code can be found in the flask-jwt-auth repository.

Cheers!

Initializing flask-login

Setting up Flask-Login via the application factory pattern is no different from using any other Flask plugin (or whatever they’re called now). This makes setting up easy: all we need to do is make sure Flask-Login is initialized in __init__.py along with the rest of our plugins, as we do with Flask-SQLAlchemy:

"""Initialize app."""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager


db = SQLAlchemy()
login_manager = LoginManager()


def create_app():
    """Construct the core app object."""
    app = Flask(__name__, instance_relative_config=False)

    # Application Configuration
    app.config.from_object('config.Config')

    # Initialize Plugins
    db.init_app(app)
    login_manager.init_app(app)

    with app.app_context():
        from . import routes
        from . import auth
        from .assets import compile_assets

        # Register Blueprints
        app.register_blueprint(routes.main_bp)
        app.register_blueprint(auth.auth_bp)

        # Create Database Models
        db.create_all()

        # Compile static assets
        if app.config['FLASK_ENV'] == 'development':
            compile_assets(app)

        return app
__init__.py

This is the minimum we need to set up Flask-Login properly.

Похожее:  Carprice. Как это работает в 2021 году | Пикабу

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *