# 简单的用户名密码登录获取token的方式
import logging
from flask import Flask, request, g, make_response, jsonify
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired
# from flask_restful import Api, Resource
app = Flask(__name__)
# 用户名密码方式认证,仅用于登录
basic_auth = HTTPBasicAuth()
# Token方式认证
token_auth = HTTPTokenAuth(scheme="Bearer")
users = [
{'username': 'Tom', 'password': '111111'},
{'username': 'Michael', 'password': '123456'}
]
# 用户登录后的token字典
# tokens={'id1': 'token1', 'id2': 'token2','id3': 'token3'}
tokens = {}
# 定义token加密、过期时间、盐SALT。例如SECRET_KEY="很长的一段密码" TOKEN_EXPIRATION=7200(为了验证有效期设为30秒) SALT= "我加的盐"
SECRET_KEY = "很长的一段密码"
TOKEN_EXPIRATION = 30
SALT = "我加的盐"
# token序列化签名方法
token_serializer = Serializer(SECRET_KEY, TOKEN_EXPIRATION)
# 创建token ,将生成的token添加到tokens列表中,这里用户名为id。如用户id存在,则更新token,旧token失效,不存在则生成新token,添加到tokens字典中
# 验证用户名密码是否正确
@basic_auth.get_password
def get_password(username):
for user in users:
if user['username'] == username:
return user['password']
return None
'''
# 登录成功返回成功信息,data中包含token(basic_auth仅用于登录)
# PostMan中调试Authorization中选择Basic Auth,输入用户名密码。
# curl --location --request POST 'http://127.0.0.1:5000/login' --header 'Authorization: Basic VG9tOjExMTExMQ=='
# 登录通过后根据用户名生成token
'''
@app.route('/login', methods=['POST'])
@basic_auth.login_required
def index():
token = create_token(basic_auth.username())
return jsonify({'code': 1, 'msg': 'success', 'data': token})
# 登录失败返回错误信息(basic_auth仅用于登录,实际包含error_handler所有basic_auth认证错误)
@basic_auth.error_handler
def errornamepaswoed():
return make_response(jsonify({'code': 0, 'msg': 'Failed', 'data': '错误的用户名或密码'}), 401)
def create_token(username):
token = token_serializer.dumps({'username': username}, SALT)
app.logger.debug(token)
tokens[username] = token
return token.decode('ascii')
# token 认证
# token loads后解析的是签名字典 {'username': 'Tom'},经过时效和错误签名验证后,检查当前用户名data['username']——即Tom是否在tokens字典中。Tom为示例用户名。
# 除用户名外,可以更多的签名,create_token生成token的签名(字典)和验证比较的签名要一致
@token_auth.verify_token
def verify_token(token):
g.user = None
app.logger.debug(token)
try:
data = token_serializer.loads(token, SALT)
except SignatureExpired:
app.logger.debug('SignatureExpired')
return False # valid token, but expired
except BadSignature:
app.logger.debug('BadSignature')
return False # invalid token
except:
return False
app.logger.info(data)
if 'username' in data:
app.logger.debug("data['username']:"+data['username'])
if data['username'] in tokens:
g.user = data['username']
return True
else:
return False
@token_auth.error_handler
def errortoken_auth():
return make_response(jsonify({'code': 0, 'msg': 'Failed', 'data': '令牌无效'}), 401)
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good Python tutorial on the web',
'done': False
}
]
# token接口范例
@app.route('/tasks', methods=['GET'])
@token_auth.login_required
def get_tasks():
return jsonify({'tasks': tasks})
if __name__ == "__main__":
app.run(debug=True)
handler = logging.FileHandler('flask.log', encoding='UTF-8')
handler.setLevel(logging.DEBUG)
logging_format = logging.Formatter(
'%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
handler.setFormatter(logging_format)
app.logger.addHandler(handler)