近日项目渐进收尾,在最后的RBAC和token测试中发现了一些小问题,在token的交互中,发现一旦重启服务器后,之前生成的token就会失效了.这在我们的日常使用中是绝对不允许的,否则假如一个人在使用着app,我们服务器更新了,当他再次访问请求的时候发现自己要重新登录了,这样带来了很不好的用户体验,所以需要改进.但是考虑到既然实用可token的JWT机制,抛弃了session和cookie的保存连接机制就要无状态到底.所以就全程没有将token做一个有状态的机制处理.
解决思路
在我们使用现在成熟的JWT生成token时有一个很重要的东西priv_key,这是一个JWK类的数据,它被封装成了一个类.我们可以在python上通过如下输出它的值:
key = jwk.JWK.generate(kty='EC', crv='P-256')
key.export(private_key=False)
这是它的值:
‘{“y”:“VYlYwBfOTIICojCPfdUjnmkpN-g-lzZKxzjAoFmDRm8”,
“x”:“3mdE0rODWRju6qqU01Kw5oPYdNxBOMisFvJFH1vEu9Q”,
“crv”:“P-256”,“kty”:“EC”}’
而之前的机制是,每次重启服务器就执行一次generateJWK的语句,因此每次它生成的JWK里的值会因y和x的值不同得到不同的JWK,因此再去验证的时候,你携带验证的priv_key参数已经不是你最初的那个了,所以它就验证不成功了.
最终我采用了一个比较笨但是比较实用的方法,就是将priv_key预先生成好,然后每次进行token的各种操作时,所携带的JWK类的秘钥就是我们这个预先生成好的priv_key,就使得token只在它的有效期过期时才失效,而不在重启服务器后就失效.
解决代码之python
import python_jwt as jwt, jwcrypto.jwk as jwk ,datetime
key = {"d":"igkREvy4tJjCjdttFZzfVcsJO0Wj0MGtxZFcremC5bNCibqQFrp-pRGkjrJIMxSiXYcaXXyVu5L11MvsKWVKA9lWhAiX8gbJ9cXirsWtIlhutO_Lv2X1kOBlJyQkdb6oPuOi5VUcXuAjWFRUvH5P60UJA1yXRZMn9gzxgMSDErGkhnFQejxBE5Qde3mUxf4pm7ysvq9eZ9xPhferl6oZ_QF60Ajj5dcJ8DWLCIftqUSwNnbMhl0Wa94PGje3kkslt1JkIaaj4ZeAL3oKmxm__hq7pG0cWGgrp6GJTOoiIOy9KHP8iaGN4GQ2diUp1iBSNFwjgN1I7RzTzq19DewIAQ","dp":"OqlXvoSVF6boqYTKhcDNQnjE-ImQWqe753BhV_SQSSeb5wlw-9O_fu23C9HyG1JCEQuJmdgm9lpiI4qwUZimuSnEOZ-FyXL440dRCNw9rew-UnTkHxaTu1ATaBtM-eFrzbtjOv9O99ITQTSCvnkDVzxuaprddstOWbJH07Bm9gE","dq":"VpCAsfGOEpxQHv__AihrJNW-5XpB1E2lxGVnM0bSlAhlMY9LRRtdr93asz7A2TB_wcSk67MgP3UeAGk2buS2C89Vsl6LMeYQQFrxcT2YyobUeRUrKtgIYsoSbHLVsqUHkM3oSqTxYOPg9OQmf-oL3jq3hhtZT0T3HriNMN_ndqk","e":"AQAB","kty":"RSA","n":"4uXpp92owv-SHgLRgboYflOX63Irhe-hU21cn25uaH6Er-nFEJHQWrdDExaU3sIS1wF54nuinazfIu2Ndc56feVuy2G2bwWCTwbss_34bGuEjGBRQeBQEtas7IBwwzbisTcW9FOwDBmleAECLPChjycoASqCnUaGGeUOH8H5MFXc4xcaDnSYG3ZKfzTgfqsAsp2__DIyB39T8ez0Ey9ux7DVjkHZ_2V7NJ9f2N1kY3TpczayHaa4I9FdGzKe6uv7KbWHK1V7Mml-JowagXIKRx30aaBtsdRNE3ICHi3vBS3VSzwGEsPk53U-x7Oer5NusXbE133hTX-j4vTgZDIpCw","p":"8daGAzGb74KGePZCCKcj4iTuzmSpiv3-_P5B3pE6DJdkOTjMR4MWzC6KCHyLaetxHfZpoU50NlK_oedLc0UCZX5CThlF9DEvn2Gb_8NMQOWDbuztLKquC_IhVmhWRTAQef0FLOv7ipa_ZYej72CJ2fWfpv_jbTYcU45VJ9w6ZgE","q":"8C9rleVhoglOopNKzrOKDMFlLX1puPtiN4a8rhWnPmrV1rCWDKTyCDBSusfm8PiYzQVnqTUme3DoQlJbvH1uQKeIXSscJBVaX8IcfCcgYtdH1cq4xWDBeNoJLMEH_jVvWcHBwD2xEupjBtyeBdCzDR7i60PXXPlDR9Ufckplxws","qi":"NLFbHCmgEaNuq17i4u0BDIYa8r0GiIYubT-M538lLtOM2CUCOax1UdUoihb0e6fhAQcZjQGayJCNYpNpsHBxt3pY2j4ygiqB3muEmS7-SlkYKeVxEg_q8LbZ8RxBzIQ5ZOQeoZJf5SElRa77wInSk2-pGGaU9RkruY8Gwd6ysEU"}
# 原来的priv_key里面的数据
tokenKey = jwk.JWK(**key) # 生成JWK对象
payload = {'message':'helloWord!'} # 这是自己添加的数据
token = jwt.generate_jwt(payload, tokenKey, 'RS256', datetime.timedelta(minutes=100)) # 生成SMSCodetoken有效期为60S
print(token)
至此你就可以生成一个不受服务器限制的token啦.