继续上一章所讲,上一章咱们最后面说道,虽然这个是很小的程序,但还有好几个要优化的地方。先复制一下老的view.py代码。python
1 # coding:utf-8 2 from flask import Flask, request, jsonify 3 from model import User, db_session 4 import hashlib 5 import time 6 import redis 7 8 app = Flask(__name__) 9 redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') 10 11 12 @app.route('/') 13 def hello_world(): 14 return 'Hello World!' 15 16 17 @app.route('/login', methods=['POST']) 18 def login(): 19 phone_number = request.get_json().get('phone_number') 20 password = request.get_json().get('password') 21 user = User.query.filter_by(phone_number=phone_number).first() 22 if not user: 23 return jsonify({'code': 0, 'message': '没有此用户'}) 24 25 if user.password != password: 26 return jsonify({'code': 0, 'message': '密码错误'}) 27 28 m = hashlib.md5() 29 m.update(phone_number) 30 m.update(password) 31 m.update(str(int(time.time()))) 32 token = m.hexdigest() 33 34 redis_store.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1}) 35 redis_store.set('token:%s' % token, user.phone_number) 36 redis_store.expire('token:%s' % token, 3600*24*30) 37 38 return jsonify({'code': 1, 'message': '成功登陆', 'nickname': user.nickname, 'token': token}) 39 40 41 @app.route('/user') 42 def user(): 43 token = request.headers.get('token') 44 if not token: 45 return jsonify({'code': 0, 'message': '须要验证'}) 46 phone_number = redis_store.get('token:%s' % token) 47 if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'): 48 return jsonify({'code': 2, 'message': '验证信息错误'}) 49 50 nickname = redis_store.hget('user:%s' % phone_number, 'nickname') 51 return jsonify({'code': 1, 'nickname': nickname, 'phone_number': phone_number}) 52 53 54 @app.route('/logout') 55 def logout(): 56 token = request.headers.get('token') 57 if not token: 58 return jsonify({'code': 0, 'message': '须要验证'}) 59 phone_number = redis_store.get('token:%s' % token) 60 if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'): 61 return jsonify({'code': 2, 'message': '验证信息错误'}) 62 63 redis_store.delete('token:%s' % token) 64 redis_store.hmset('user:%s' % phone_number, {'app_online': 0}) 65 return jsonify({'code': 1, 'message': '成功注销'}) 66 67 68 @app.teardown_request 69 def handle_teardown_request(exception): 70 db_session.remove() 71 72 if __name__ == '__main__': 73 app.run(debug=True, host='0.0.0.0', port=5001)
其中验证token的方法,已经重叠了,python教咱们,永远不要重复本身的代码,这是很丑陋的行为。今天咱们把它换成一个装饰器,而后再把redis调整一下,看看代码会不会简洁不少。redis
1 # coding:utf-8 2 from flask import Flask, request, jsonify 3 from model import User, db_session 4 import hashlib 5 import time 6 import redis 7 from functools import wraps 8 9 app = Flask(__name__) 10 redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') 11 12 13 def login_check(f): 14 @wraps(f) 15 def decorator(*args, **kwargs): 16 token = request.headers.get('token') 17 if not token: 18 return jsonify({'code': 0, 'message': '须要验证'}) 19 20 phone_number = redis_store.get('token:%s' % token) 21 if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'): 22 return jsonify({'code': 2, 'message': '验证信息错误'}) 23 24 return f(*args, **kwargs) 25 return decorator 26 27 28 @app.route('/login', methods=['POST']) 29 def login(): 30 phone_number = request.get_json().get('phone_number') 31 password = request.get_json().get('password') 32 user = User.query.filter_by(phone_number=phone_number).first() 33 if not user: 34 return jsonify({'code': 0, 'message': '没有此用户'}) 35 36 if user.password != password: 37 return jsonify({'code': 0, 'message': '密码错误'}) 38 39 m = hashlib.md5() 40 m.update(phone_number) 41 m.update(password) 42 m.update(str(int(time.time()))) 43 token = m.hexdigest() 44 45 pipeline = redis_store.pipeline() 46 pipeline.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1}) 47 pipeline.set('token:%s' % token, user.phone_number) 48 pipeline.expire('token:%s' % token, 3600*24*30) 49 pipeline.execute() 50 51 return jsonify({'code': 1, 'message': '成功登陆', 'nickname': user.nickname, 'token': token}) 52 53 54 @app.route('/user') 55 @login_check 56 def user(): 57 token = request.headers.get('token') 58 phone_number = redis_store.get('token:%s' % token) 59 60 nickname = redis_store.hget('user:%s' % phone_number, 'nickname') 61 return jsonify({'code': 1, 'nickname': nickname, 'phone_number': phone_number}) 62 63 64 @app.route('/logout') 65 @login_check 66 def logout(): 67 token = request.headers.get('token') 68 phone_number = redis_store.get('token:%s' % token) 69 70 pipeline = redis_store.pipeline() 71 pipeline.delete('token:%s' % token) 72 pipeline.hmset('user:%s' % phone_number, {'app_online': 0}) 73 pipeline.execute() 74 return jsonify({'code': 1, 'message': '成功注销'}) 75 76 77 @app.teardown_request 78 def handle_teardown_request(exception): 79 db_session.remove() 80 81 if __name__ == '__main__': 82 app.run(debug=True, host='0.0.0.0', port=5001)
加了一个装饰器,是否是简洁了不少?每次须要验证的时候,只须要一个login_check就能够了,这样就变得很是简洁,并且脉络清晰。redis也改为了管道执行,pipeline,防止执行到一半,被掐断。数据库
但是,但是,我仍是以为不简洁,看user, logout的代码中重复的地方。json
token = request.headers.get('token') phone_number = redis_store.get('token:%s' % token)
每次都有这两句,要是未来还有其余值怎么办?上面不刚说,永远不要重复本身的代码吗?flask
好,咱们再写一个函数,看下面代码session
1 # coding:utf-8 2 from flask import Flask, request, jsonify, g 3 from model import User, db_session 4 import hashlib 5 import time 6 import redis 7 from functools import wraps 8 9 app = Flask(__name__) 10 redis_store = redis.Redis(host='localhost', port=6380, db=4, password='dahai123') 11 12 13 def login_check(f): 14 @wraps(f) 15 def decorator(*args, **kwargs): 16 token = request.headers.get('token') 17 if not token: 18 return jsonify({'code': 0, 'message': '须要验证'}) 19 20 phone_number = redis_store.get('token:%s' % token) 21 if not phone_number or token != redis_store.hget('user:%s' % phone_number, 'token'): 22 return jsonify({'code': 2, 'message': '验证信息错误'}) 23 24 return f(*args, **kwargs) 25 return decorator 26 27 28 @app.before_request 29 def before_request(): 30 token = request.headers.get('token') 31 phone_number = redis_store.get('token:%s' % token) 32 if phone_number: 33 g.current_user = User.query.filter_by(phone_number=phone_number).first() 34 g.token = token 35 return 36 37 38 @app.route('/login', methods=['POST']) 39 def login(): 40 phone_number = request.get_json().get('phone_number') 41 password = request.get_json().get('password') 42 user = User.query.filter_by(phone_number=phone_number).first() 43 if not user: 44 return jsonify({'code': 0, 'message': '没有此用户'}) 45 46 if user.password != password: 47 return jsonify({'code': 0, 'message': '密码错误'}) 48 49 m = hashlib.md5() 50 m.update(phone_number) 51 m.update(password) 52 m.update(str(int(time.time()))) 53 token = m.hexdigest() 54 55 pipeline = redis_store.pipeline() 56 pipeline.hmset('user:%s' % user.phone_number, {'token': token, 'nickname': user.nickname, 'app_online': 1}) 57 pipeline.set('token:%s' % token, user.phone_number) 58 pipeline.expire('token:%s' % token, 3600*24*30) 59 pipeline.execute() 60 61 return jsonify({'code': 1, 'message': '成功登陆', 'nickname': user.nickname, 'token': token}) 62 63 64 @app.route('/user') 65 @login_check 66 def user(): 67 user = g.current_user 68 69 nickname = redis_store.hget('user:%s' % user.phone_number, 'nickname') 70 return jsonify({'code': 1, 'nickname': nickname, 'phone_number': user.phone_number}) 71 72 73 @app.route('/logout') 74 @login_check 75 def logout(): 76 user = g.current_user 77 78 pipeline = redis_store.pipeline() 79 pipeline.delete('token:%s' % g.token) 80 pipeline.hmset('user:%s' % user.phone_number, {'app_online': 0}) 81 pipeline.execute() 82 return jsonify({'code': 1, 'message': '成功注销'}) 83 84 85 @app.teardown_request 86 def handle_teardown_request(exception): 87 db_session.remove() 88 89 if __name__ == '__main__': 90 app.run(debug=True, host='0.0.0.0', port=5001)
咱们在代码中加了一个before_request,这个函数就是在每一个request发起的时候,若是已经验证了,咱们把当前g.current_user和g.token设置一下,这样每次须要获取当前用户的时候,直接找g.current_user就能够了,是否是简单了太多太多?好了,今天到此为止,下一章,咱们讲怎么利用alembic修改数据库。app