现在很多框架都实现前后端分离,主要为了适应以下几个目的:
1,前后端的分离,可以使前端开发和后端开发更加分工明确,而不是后端还需要在视图模板中加入很多{% XXXX %}标签
2,是为了适应跨域调用或者多客户端调用,如你的手机应用调用某个接口,大都是调用第三方api等
所以在整合JWT,让框架具有更多的适应性。JWT 说简单就是基于token的权限验证;flask 有提供json的支持,可是对象转化是一个大问题;
其实,也不用彻底转化为对象,能满足字典存取值就足够;如果有时间就考虑完善这个整合框架成一个快捷开发框架。
第一步:flask 整合 flask_login
1) 配置user类
class User(UserMixin,db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password= db.Column(db.String(128)) avatar_hash = db.Column(db.String(32)) session_token='123213dsfw3432' def __init__(self,id,username,email): self.id = id self.username = username self.email = email def get_id(self): return self.session_token def __repr__(self): return '<User %r>' % self.username
其中的get_id(self)是针对token验证提供,目的是根据token去数据库查询用户,但其实是没用作用的,因为数据库根本就没存这东西,也没有在
@login_manager.user_loader定义下函数使用;
2) 配置 view的回调函数
@login_manager.user_loader def load_user(userid): user = getUserById(userid) return user @login_manager.request_loader def load_user_from_request(request): api_key = request.headers.get('Authorization') print(api_key) if api_key: obj = jwtDecoding(api_key) user = obj['some'] if user: user = getUserById(user['id']) return user else: print("is exception !!!!"+str(obj['error_msg'])) return None
@login_manager.request_loader 是对每次请求时,对应请求头的token做验证的,具体可以去看看官方文档,不再重复。
3)配置启动apps
具体的内容如下:
from flask import Flask, request,make_response from flask_login import LoginManager login_manager = LoginManager() def create_app(config=None): app = Flask(__name__) #app.config.from_object(config) if config is not None: app.config.from_pyfile(config) # send CORS headers @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Origin', '*') if request.method == 'OPTIONS': response.headers['Access-Control-Allow-Methods'] = 'DELETE, GET, POST, PUT' headers = request.headers.get('Access-Control-Request-Headers') if headers: response.headers['Access-Control-Allow-Headers'] = headers ##response.headers['Authorization'] = 'xiaominggessdfs3432ds34ds32432cedsad332e23' return response from apps.model1 import db db.init_app(app) login_manager.session_protection = "strong" login_manager.init_app(app) from apps.test1.view import init_api init_api(app) return app
到这里说明 flask_login 整合ok了
第二步,整合pyjwt
1)首先定义一个jwt使用的工具类:
import jwt import datetime import hashlib SECRECT_KEY = 'secret' def md5Encoding(youstr): m=hashlib.md5() m.update(youstr) encodingstr=m.hexdigest() print(encodingstr) # 生成jwt 信息 def jwtEncoding(some,aud='webkit'): datetimeInt = datetime.datetime.utcnow() + datetime.timedelta(seconds=180) print(datetimeInt) option = { 'exp':datetimeInt, 'aud': aud, 'some': some } encoded2 = jwt.encode(option, SECRECT_KEY, algorithm='HS256') return encoded2 # userInfo = { # "id":12, # "username":"2234", # "email":"23423dsd" # } # # listr = jwtEncoding(userInfo) # print(listr.decode()) # 解析jwt 信息 def jwtDecoding(token,aud='webkit'): decoded = None try: decoded = jwt.decode(token, SECRECT_KEY, audience=aud, algorithms=['HS256']) except jwt.ExpiredSignatureError : print("erroing.................") decoded = {"error_msg":"is timeout !!","some":None} except Exception: decoded ={"error_msg":"noknow exception!!","some":None} print("erroing2.................") return decoded
2)整合pycharm到flask_login
其实上面红色的代码就是说明已经整合到flask_login里面去了,你是不是觉得很简单,当然还得提供一个登陆的功能,生成token:
@app.route('/login', methods=['GET', 'POST']) def login(): str = request.get_json() print(str) name = str['username'] admin = User.query.filter_by(username=name).first() #这里需要重新修改成成缓存里取,减少处理时间 userInfo = { "id":admin.id, "username":admin.username, "email":admin.email } if admin == None: return jsonify(trueReturn("{'ok':Flase}", "not the user")) else: #request.headers['Authorization']='liuliuyyeshibushidslfdslfsdkfkdsf23234243kds' #login_user(admin) token = jwtEncoding(userInfo) print(token) return jsonify(trueReturn("{'ok':True,'token':"+token.decode()+"}", "you are sucess"))
如果验证出错就会在 obj = jwtDecoding(api_key) 里面报错,所以在这里,你需要捕捉错误,并提示出来,工具类只是简单捕捉,这一块还需要完善一点。
3)例子演示
1,登陆:
可以看到成功,并返回token了
2,操作一些有权限要求的接口:
@app.route('/cun') @login_required #登陆验证要求 def getUser2(): user=utils._get_user() ##通过flask_login manage 中获取用户 print(user.__dict__) return jsonify(trueReturn("{'ok':True}", "cun success!!!!!"))
请求前,必须加消息头Authorization ,里面的内容为token字符串,也可以自定义规范格式
3,过期效果:
jwt里面加了时间期限
有一个缺陷就是缺少日期的token 日期的刷新功能,登陆后一段时间就过期了,应该加个每次请求一段时间就刷新token的功能,
这些对于你们来说,就是小事改改就行。
源码给你们提供出来:https://files.cnblogs.com/files/minsons/teston2.zip (下载)
参考:
pyJWT:https://pyjwt.readthedocs.io/en/latest/usage.html
flask_login:https://flask-login.readthedocs.io/en/latest/#flask_login.confirm_login
flask_jwt :http://pythonhosted.org/Flask-JWT/ 这个源两年多没更新了,里面其实也是调用pyjwt,建议不要用了
flask-httpauth :http://flask-httpauth.readthedocs.io/en/latest/ 也可以考虑用flask-httpauth 整合pyjwt ,也是简单挺好用的东西