flask restful-api實現及基於flask-httpauth實現基礎權限管控(三)

本系列教程分爲四個階段

1.flask restful web service

2.flask restful api

3.flask httpauth實現權限管控

4.uwsgi管理flask應用


前兩篇文章中,我們學習了基礎的web services和restful api的開發實現,在實現接口開發後,我們一般需要對接口進行加密認證,避免接口外泄導致的數據丟失等問題。

在原文中代碼分爲幾部分說明,並不直觀,而且影響連續性的學習,所以這裏筆者直接通過整段代碼的形式進行學習,並對代碼中的關鍵點進行拆分講解。

下面是實現httpauth及token認證的代碼:

import time

from flask import Flask, jsonify, url_for, request, g
from flask_restful import Api, abort
# flask SQLAlchemy模塊,實現ORM框架操作
from flask_sqlalchemy import SQLAlchemy
# flask自帶httpauth模塊,BasicAuth和tokenAuth子模塊
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
# 密碼散列加密模塊
from passlib.apps import custom_app_context as pwd_context
# jwt-- token生成模塊
import jwt
# werkzeug密碼加密模塊,有興趣的可以自行了解
# from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
api = Api(app)

# 關於flask SQLAlchemy實現ORM框架操作的一些基礎配置
app.config['SECRET_KEY'] = 'dqwecf29vbneuirjnf2i3n0f2i302n'
# 數據庫連接信息配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
# 是否自動提交sql執行
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
# 是否顯示修改回執
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# SQLAlchemy實例化
db = SQLAlchemy(app)
# 引入基礎認證、token認證模塊
auth = HTTPBasicAuth()
token_m = HTTPTokenAuth()

class User(db.Model):
    #表名
    __tablename__ = 'users'
    #表字段名對應賦值屬性
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(32), index=True)
    password_hash = db.Column(db.String(64))
    # print(id, username, password_hash)

    # def __init__(self, username, password_hash):
    #     self.username = username
    #     self.password_hash = password_hash

    #生成密碼散列方法
    def hash_password(self, password):
        self.password_hash = pwd_context.encrypt(password)

    #校驗密碼方法
    def verify_password(self, password):
        return pwd_context.verify(password, self.password_hash)

    #生成token方法
    def generate_auth_token(self):
        # print(time.time())
        print("self id ", self.id)
        print(self.username)
        print(self.password_hash)
        return jwt.encode(
            {'id': self.id, 'exp': time.time() + 600},
            app.config['SECRET_KEY'], algorithm='HS256')

    #校驗token方法
    @staticmethod
    def verify_auth_token(token):
        try:
            data = jwt.decode(token, app.config['SECRET_KEY'],
                              algorithms=['HS256'])
            print(data)
        except Exception as e:
            print(e)
            return False
        user = User.query.get(data['id'])
        print("user", user)
        return user

# 在初次請求時,進行數據的表創建
# 實際開發中,此處一般會在數據庫中已經完成,研發人員只需要關注表結構,並進行對應的字段操作即可
@app.before_first_request
def create_db():
    #刪除
    db.drop_all()
    #創建
    db.create_all()

# 根據密碼登錄認證裝飾器進行請求攜帶的密碼信息校驗
@auth.verify_password
def verify_password(username_or_token, password):
    user = User.query.filter_by(username=username_or_token).first()
    if not user or not user.verify_password(password):
        return False
    g.user = user
    return True

# 根據token登錄認證裝飾器進行請求攜帶的token校驗
@token_m.verify_token
def verify_token(token):
    user = User.verify_auth_token(token)
    g.user = user
    if not user:
        return False
    return True

# 獲取用戶訪問信息,並根據判斷信息,添加新用戶
@app.route('/api/users', methods=['POST'])
def new_user():
    username = request.json.get('username')
    password = request.json.get('password')
    if username is None or password is None:
        abort(400)  # missing arguments
    if User.query.filter_by(username=username).first() is not None:
        print('existing user')
        abort(400)  # existing user
    user = User(username=username)
    user.hash_password(password)
    db.session.add(user)
    db.session.commit()
    return (jsonify({'username': user.username}), 201,
            {'Location': url_for('get_user', id=user.id, _external=True)})

# 查詢指定用戶方法
@app.route('/api/users/<int:id>')
def get_user(id):
    user = User.query.get(id)
    if not user:
        abort(400)
    return jsonify({'username': user.username})

# 查詢所有用戶方法
@app.route('/api/users', methods=['GET'])
def get_all_user():
    users = User.query.all()
    if not users:
        abort(400)
    return jsonify(["{0}, {1}".format(user.username, user.password_hash) for user in users])

# 基於密碼生成token方法
@app.route('/api/token')
# 密碼登錄驗證裝飾器
@auth.login_required
def get_auth_token():
    token = g.user.generate_auth_token()
    return jsonify({'token': token.decode('ascii'), 'duration': 600})

# token認證方法
@app.route('/api/resource')
# token登錄驗證裝飾器
@token_m.login_required
def get_resource():
    return jsonify({'data': 'Hello, %s!' % g.user.username})

@app.errorhandler(400)
def error(e):
    print(e)
    return '錯誤請求', 400

if __name__ == '__main__':
    app.run('0.0.0.0', 8080)


以上代碼塊中,讀者可直接拷貝到IDEA中運行查看效果即可。
對應的需要了解的有,在ORM框架中,使用方法調用代替原生sql執行,如:

查詢
User.query.filter_by(username=username).first()
增加
user = User(username=username)
user.hash_password(password)
db.session.add(user)
db.session.commit()

關於具體的基於SQLAlchemy實現的ORM框架使用方法,請各位自行查詢資料瞭解學習。
代碼塊中已經對相應的模塊進行說明,在實際調用中代碼名稱已經是自解釋的,如若不瞭解,可以再搜索相關資料。

本文僅對flask的auth實現進行演示,不再過多的闡述,成年人的學習不應是喂什麼吃什麼,而是自己動手,豐衣足食。

感謝觀看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章