更多的有关FLASK API的事

2019-06-24  本文已影响0人  浪尖的游鱼

书接上文hello Flask


养成书写python项目的良好习惯

'''
创建虚拟环境以隔离开发环境
'''
#install virtualenv
> pip3 install virtualenv
#在当前目录创建虚拟环境,by python3
> virtualenv ll_env --python = python3
#ll_env是环境名,linux一般习惯取名.env,这样就是隐藏文件了, --python=python3是为了有多个python环境准备的,还有一些其他的知识,自行查询资料
#linux进入虚拟环境
> source .env/bin/activate
#window进入虚拟环境
> .\ll_env\Scripts\activate
#退出
> deactivate

注意:以上创建的是空的环境,需要重新下flask包

参考

示例代码

插件介绍Flask-RESTful

安装

> pip3 install Flask-RESTful

最好的参考
官方文档

我们来测试一下

from flask import Flask
from flask_restful import Resource,Api

app = Flask(__name__)
#定义一个程序的入口点,你可能需要用一个Flask应用初始化它
api = Api(app)

#定义一个抽象的RESTful资源,它继承自Resource
class Student(Resource):
    def get(self,name):
        return {'Student':name}
    
api.add_resource(Student,'/student/<string:name>')

app.run(port=5000)

接下来用flask_restful重写上一篇文章的逻辑

from flask import Flask,request
from flask_restful import Resource,Api

app = Flask(__name__)
#定义一个程序的入口点,你可能需要用一个Flask应用初始化它
api = Api(app)

items = [

]

#定义一个抽象的RESTful资源,它继承自Resource
class Item(Resource):
    def get(self,name):
        item = next(filter(lambda x:x['name'] == name,items),None)
        return {'item':item},200 if item is not None else 404
    def post(self,name):
        if next(filter(lambda x:x['name'] == name,items),None) is not None:
            return {'Message':'An item with name "{}" already exists.'.format(name)},400
        date = request.get_json(force = True)
        '''
        force = True,不检查header的content-type='application/JSON'
        silent – 静默解析错误并返回None
        '''
        item = {'name':name,'price':date['price']}
        items.append(item)
        return item,201
    
class ItemList(Resource):
    def get(self):
        return items

api.add_resource(Item,'/item/<string:name>')
api.add_resource(ItemList,'/items')

app.run(port=5000,debug=True)

插件介绍Flask-JWT

JWT全名是JSON web Token,是通过Token实现的用户权限认证机制。并编码传输的数据
安装

> pip3 install Flask-JWT

官方参考
官方文档
示例

from flask_jwt import JWT,jwt_required
from security import authenticate,identity
#可以用os.urandom(24)生成随机的密钥
app.secret_key = b"\x8e\xaes\x01\xb7'p\xa81\xb7\x92\xca\xc5\x1a9^\xa3\x18\xb3\rOx<x"
jwt = JWT(app,authenticate,identity)#导入用户认证机制,会创建/auth

我们可以通过JWT这个类自行创建一个'/auth'目录下的认证机制
但是需要我们提供两个方法:authenticate,identity
authenticate:POST用户名和密码,返回用户信息
identity:根据之前校验取得的凭证返回用户
创建文件./security.py和./user.py示例如下(当然正常情况下,第一不存用户密码,第二应该与数据库进行交互,这里只做示例,所以也不多深究)

from werkzeug.security import safe_str_cmp
#这种比较方法可以预防编码不同
from user import User
users = [
    User(1,"Bomb","qsc")
]
username_mapping = { u.username:u for u in users }
userid_mapping = { u.id:u for u in users }

def authenticate(username,password):
    #通过账密进行用户认证
    user = username_mapping.get(username,None)
    if user and safe_str_cmp(user.password , password):
        return user

def identity(payload):
    #根据凭证取得用户
    user_id = payload['identity']
    ccs = userid_mapping.get(user_id,None)
    return userid_mapping.get(user_id,None)

用户信息./user.py,一个非常简单的只有账密和id的类

class User():
    def __init__(self,_id,username,password):
        self.id = id
        self.username = username
        self.password = password

可以看到上文伪造了一个实际存在的用户Bomb,我们可以POST下/auth,看下机制。


返回Token

然后更改./app.py,要求某些请求需要Token认证

from flask_jwt import JWT,jwt_required
class Item(Resource):
    @jwt_required()
    def get(self,name):
        item = next(filter(lambda x:x['name'] == name,items),None)
        return {'item':item},200 if item is not None else 404

这里我们引入了装饰器jwt_required,关于装饰器可以阅读下文的连接

此时我们再请求GET /item/<name>,我们得到的回覆如下:


401错误

复制之前的TOKEN,我们来进行验证


当我们拥有令牌时

去使用DEL和PUT

这里提前说一下:HTTP动作是人为定义的,但开发时请尽力符合规范。

    @jwt_required()
    def delete(self,name):
        global items
        items = list(filter(lambda x : x['name'] != name,items))
        return {'message': 'Item deleted'}
        
    @jwt_required()
    def put(self, name):
        date = request.get_json()
        #Item.parser.parse_args
        #data = Item.parser.parse_args()
        # Once again, print something not in the args to verify everything works
        item = next(filter(lambda x: x['name'] == name, items), None)
        if item is None:
            item = {'name': name, 'price': data['price']}
            items.append(item)
        else:
            item.update(data)
        return item

这里注释部分引入了新机制from flask_restful import reqparse,我们可以通过这个包约束请求的规范,俗称request parsing。

#定义约束
    parser = reqparse.RequestParser()
    parser.add_argument('price',
        #转化为float类型
        type=float,
        #必填
        required=True,
        #异常返回值
        help="This field cannot be left blank!"
    )

通过这个我们来改写下PUT方法

    #@jwt_required()
    def put(self, name):
        data = Item.parser.parse_args()
        print(data)
        # Once again, print something not in the args to verify everything works
        item = next(filter(lambda x: x['name'] == name, items), None)
        if item is None:
            item = {'name': name, 'price': data['price']}
            items.append(item)
        else:
            item.update(data)
        return item

这种方法好处在于不需要我们去校验request的规范,并且只会筛选已经定义的规范
总结,我们学到了:
如何规范的创建一个Python项目
如何规范的创建一个Resource对象
如何加入TOKEN验证
如何规范处理REQUEST请求
下一章
flask与DB交互

回到目录

上一篇下一篇

猜你喜欢

热点阅读