想写一个web应用API不知从何下手,网上各种查找文章,最后还是一个同事推荐用的Flask。
在不断的增加需求之后,遇到了一个叫Json Web Token的署名认证的一个机制。
困扰了很久,最后是借鉴了Google上的一篇文章实现了认证功能,这里分享给大家。
今年是2020年,所以密码就设定为hello2020.
User = {
'よう':{
#hello2020
'password':'pbkdf2:sha256:150000$GQ6cAjgw$c4bbb17a66188035d2886f4f64f589a3ecb17091707c0cdc99276936175fa7d1'
}
}
hello2020进行了哈希化,就得到了加密的一长串乱码替换密码。加密方法如下。
$python
>>> from werkzeug.security import generate_password_hash
>>> generate_password_hash('hello2020')
'pbkdf2:sha256:150000$GQ6cAjgw$c4bbb17a66188035d2886f4f64f589a3ecb17091707c0cdc99276936175fa7d1'
为了验证用户身份,所以methods设置成POST模式,以便传入用户信息。
from flask import Flask,request,make_response,jsonify
from werkzeug.security import check_password_hash
import datetime
import jwt
@api.route('/authorize',methods=['POST'])
def authorize():
input_name = request.json['name']
input_password = request.json['password']
eiji_pass = User[input_name]['password']
if not check_password_hash(eiji_pass,input_password):
return make_response('Password is incorrect',400)
先取出通过POST传进去的用户名和密码、然后再在User里面取出用户对应的密码。
通过check_password_hash()函数来验证,POST传入的用户密码和存储在User中的密码是否一致。
exp = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
encoded = jwt.encode({'name': input_name,'exp': exp}, 'SECRET_KEY', algorithm='HS256')
response = {'user':input_name,'token':encoded.decode('utf-8')}
return make_response(jsonify(response),200)
用户名和密码正确的情况下生成验证消息(token)并返回给申请的用户。
具体是由用户名和加密的值还有系统时间等组合生成。
Flask运行后、另起一窗口执行curl指令。用chrome的话这里推荐用(Talend API Tester)这个工具,非常便捷。
$ curl http://localhost:5000/authorize -X POST -H "Content-Type: application/json" -d '{"name":"よう","password":"hello2020"}'
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiXHUzMDg4XHUzMDQ2IiwiZXhwIjoxNTgwODI0MjM5fQ.pahnvq3MDJrBZUDOeTTDnusDtdnyJwfaNsHwp5oti04",
"user": "よう"
}
验证之后,用户名和密码都正确的情况下,用户手里就又了Token这把请求数据的钥匙。
为了使用手中的钥匙打开数据之门的锁,我们再下一个login_required()函数。
from flask import Flask,request,abort
import functools
import jwt
def login_required(method):
@functools.wraps(method)
def wrapper(*args, **kwargs):
header = request.headers.get('Authorization')
_,token = header.split()
try:
decoded = jwt.decode(token,'SECRET_KEY',algorithms='HS256')
username=decoded['name']
except jwt.DecodeError:
abort(400,message='Token is not valid.')
except jwt.ExpiredSignatureError:
abort(400,message='Token is expired.')
return method(username,*args, **kwargs)
return wrapper
这里面既验证了Token也验证Token的有效时间。
@api.route('/user',methods=['GET'])
@login_required
def user(username):
return '成功了就喝啤酒去!'
Token验证成功之后,将返回我们一直在请求一直得不到的信息。
curl http://localhost:5000/user -X GET -H '{"Authorization: JWT Token"}'
>>>よう: 成功了就喝啤酒去!
类似这样的一个流程,通过python语言用Flask框架写了一个可以进行JWT认证的Web应用API。
@api.route虽然这里用的是api,其实写成app同样可以把功能实现了。