使用Flask框架构建服务器端
2016-05-24 15:07
411 查看
使用Flask框架构建服务器端
使用Flask构建RESTful风格的API服务器
#
构建RESTful风格的服务器可以使用Flask-RestFul框架这个框架将资源视作一个类,我们需要提供POST,GET,PUT,DELETE等方法的具体实现,然后再绑定端点(URL)
但是我认为这样的开发体验不够便捷,我用Flask的原因是因为Flask可以非常方便的构建端点到view function的映射,所以我依然使用Flask框架作为RESTful风格API服务器的开发
准备
Flask是一个微框架,相对于Django来说,它不够完整,很多地方需要自己完成,同时它的易于扩展性可以允许我们很自由的选择第三方实现我选择了一下第三部件:
Flask-HTTPAuth 用于简单验证
SQLAlchemy 用于SQL语言的ORM
Alembic 用于管理DB版本
Passlib 用于密码管理
以上都可以使用pip安装
Here we go
RESTful风格的中心是资源,资源指的是某种实体(而不是某种动作),比如围绕着用户登陆,注册登出这样的动作应该归结为用户资源,使用POST GET DELETE PUT等方法来表达用户登陆,获取登陆状态,登出,更新登陆状态的操作。现在我们就来实现这一部分
首先我们应该在数据库里拥有User资源,也就User表
我们使用SQLAlchemy来声明数据库
首先构造base.py
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base engine = create_engine('sqlite:////tmp/iamstar.db', convert_unicode=True) db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = db_session.query_property() def init_db(): # remember import your models from Model import xxxxxx Base.metadata.create_all(bind=engine)
构造好base后,我们可以根据base来构建其他数据库模型
from sqlalchemy import Column, Integer, String, Text from sqlalchemy.orm import relationship from Model.base import Base from passlib.apps import custom_app_context as pwd_context class User(Base): __tablename__ = 'User' id = Column(Integer, primary_key=True) username = Column(String(32), index=True) password_hash = Column(String(128)) def __init__(self, username=None, password=None): self.username = username self.hash_password(password=password) def __repr__(self): return '' 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)
我们的User模型继承至Base
通过Column等方法来构建表
在我们的User模型中,我们引入了passlib库 并且添加了两个方法用于生成和验证hash密码。
有了模型之后我们可以开始着手view函数部分了
我们只实现用户的登陆和token验证部分,登出等不在本文中写
from flask import Flask, request, session, redirect, url_for, render_template, flash, abort, jsonify, g from flask.ext.httpauth import HTTPBasicAuth, HTTPTokenAuth auth = HTTPBasicAuth() from Model.User import User DEBUG = True SECRET_KEY = 'iawue8rp8q2(U*&)(&^t^&T*&^t&T(EA*' # achieve our dream app = Flask(__name__) app.config.from_object(__name__) @app.teardown_appcontext def shutdown_session(exception=None): db_session.remove() @app.route('/app/user/', methods=['GET', 'POST', 'DELETE', 'PUT']) def user(): if request.method == 'GET': return render_template('test.html', register=True) # TODO return the public_info of user_id / or info_details of mine if request.method == 'POST': # TODO register a user # username = request.json.get('username') # password = request.json.get('password') username = request.form['username'] password = request.form['password'] if username is None or password is None: return jsonify(missing_arguments=True) # missing arguments if User.query.filter_by(username=username).first() is not None: return jsonify(existing_user=True) # existing user u = User(username=username, password=password) db_session.add(u) db_session.commit() return jsonify(register=True) if request.method == 'DELETE': pass # TODO to delete a user,do not offer now if request.method == 'PUT': pass # TODO upgrade a new user's info,need logged
以上是注册用户的方法,注册用户时,用户的密码会被hash然后存储
接下来是登陆部分,我将登陆作为另一种资源单独建立了表,表中只有用户名和用户token两个域所以不贴代码
我们使用HTTPBasicAuth来构建验证函数,HTTPAuth库为我们提供了一种很棒的开发体验,我们只需像下面这样构建一个验证函数,并用@auth.verify_password修饰器修饰
@auth.verify_password def verify_password(username, password): user = User.query.filter_by(username=username).first() if not user or not user.verify_password(password): g.user = None return False g.user = user return True
之后我们只需要在要求登陆的view function上面添加@auth.login_required修饰器即可控制view functoin的权限
@auth.login_required def login(): if request.method == 'GET': return render_template('test.html', login=True) # TODO return the stage of login if request.method == 'POST': # need a Authorization hear username = g.user.username if username: l = Login(username=username) now, token = l.generate_and_save_token() db_session.add(l) db_session.commit() return jsonify(login=True, token=token, now=now) return jsonify(login=False) # TODO login and return the result,token within 600s life-circle and create time if request.method == 'DELETE': pass # TODO logout and return the result if request.method == 'PUT': pass # TODO re-login to upgrade some things
上面的代码段里,如果用户成功验证密码g.user里面就会有值否则为空
用户成功验证后,就会使用Login 数据模型中的一个方法generate_and_save_token(),给这个登陆用户生成一个token用于后续的交互。
在上面例子中,客户端发送账号密码的方式是:添加Authorization头信息
实例:
格式:Authorization: <scheme> <credentials> Authorization: Basic username:password Authorization: Token eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ2NDA1NTg2OSwiaWF0IjoxNDY0MDU1MjY5fQ.eyJpZCI6bnVsbH0.4Oe60fyM8t6BvPvdZWlNqCO3ZKXW5HHsjVmoaUkp-1E
上面的验证方法,使用第一个例子的格式就行,同时,我们可以将username:password 进行加密,在verify_password函数中写上解密方法
接着后续的用户验证方法应该使用token方式
首先引入HTTPTokenAuth库
from flask.ext.httpauth import HTTPTokenAuth token_auth = HTTPTokenAuth(scheme='Token') #注意这里的构造器参数scheme
接着和HTTPBasicAuth类似的
@token_auth.verify_token def verify_token(token): g.user = None l = Login.query.filter_by(token=token).first() if l is not None: g.user = User.query.filter_by(username=l.username) return g.user is not None if __name__ == '__main__': app.run()
在需要token验证的函数上添加@token_auth.login_required
@app.route('/app/star/<int:star_id>', methods=['GET', 'POST', 'DELETE', 'PUT']) @token_auth.login_required def star(star_id): if request.method == 'GET': return jsonify(tr=True) # TODO return the list of star by default params / or a star's info if request.method == 'POST': pass # TODO return the list of star by given params if request.method == 'DELETE': pass # TODO to delete a star,do not offer now if request.method == 'PUT': pass # TODO do not offer
客户端发送token的方式:
python Authorization: Token eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ2NDA1NTg2OSwiaWF0IjoxNDY0MDU1MjY5fQ.eyJpZCI6bnVsbH0.4Oe60fyM8t6BvPvdZWlNqCO3ZKXW5HHsjVmoaUkp-1E
相关文章推荐
- 架构漫谈(五):什么是软件
- 网站内容禁止复制和粘贴、另存为的js代码
- 腾讯云,阿里云 把网站的数据放到数据盘上
- Android官方MVP架构解读
- 个人博客选择网站空间的六个技巧
- Android官方MVP架构解读
- Css3的Media Query方法总结—让您的网站兼容手机
- 软件架构设计-五视图方法论
- OpenStack的基本概念与架构图
- 孙孙啊i 之项目实战(一) 创建BaseActivity
- 定制班第11课:Spark Streaming Driver中的ReceiverTracker架构
- 前端学习网站
- 企业为什么需要建手机网站
- iis发布网站
- 网站SEO之百度优化不得不知的铁人三项规则
- 关于MVVM
- 架构搭建篇
- .net utf-8编码向gb2312网站提交数据
- 我眼中的Android架构
- 高并发金融应用架构优化与平台创新