在第三节我们熟悉并编写了用户登录逻辑,这一节我们要实现用户状态保持,就是判断用户当前的登录状态,我们用加密cookie的方式来实现,在bottle中用response.set_cookie()
和requests.get_cookie()
来写入和读取用户cookie,非常简单,让我们在5分钟内实现它。
from bottle import run,route,template,request,response
from user import read_user
@route('/login', method = 'GET')
def index():
username = request.get_cookie('username', secret = 'usafe')
password = request.get_cookie('password', secret = 'psafe')
if read_user(username, password):
return '你已经登录'
return template('login')
@route('/login', method = 'POST')
def index():
username = request.forms.get('username')
password = request.forms.get('password')
if read_user(username, password):
response.set_cookie('username', username, secret = 'usafe', httponly = True, max_age = 600)
response.set_cookie('password', password, secret = 'psafe', httponly = True, max_age = 600)
return '登录成功'
return '账号密码错误'
run(host = 'localhost', port = 80, debug = True, reloader = True)
解释:request.get_cookie('username', secret = 'usafe')
是获取用户客户端的加密cookie,然后用自定义的安全字符串usafe
来解密,获取username。request.get_cookie('password', secret = 'psafe')
是获取用户客户端的加密cookie,然后在服务端解密password
。
response.set_cookie('username', username, secret = 'usafe', httponly = True, max_age = 600)
是写入用户浏览器cookie,把username这个变量用安全字符串usafe
加密,httponly指不允许通过javascript获取cookie,降低用户信息泄露风险,max_age = 600
指这个cookie的有效期为600秒,600秒后就会过期,用户需要重新登录。
你可能会疑惑,这种方式安全吗?
首先并不是说cookie放到客户端就一定是不安全的,对于一些在服务端多次加salt然后用RSA加密方式加密,最后放到客户端的cookie安全性还是比较高的,也就是说Cookie != 不安全。在bottle中并不推荐我们使用把敏感信息放到cookie中的做法。
image.png
也就是说bottle的cookie并没有经过强加密,我们只是用cookie实现用户登录状态的保持,想要安全?你可以自己写加密函数,把敏感信息加密后再放到cookie。
编写加密函数,存储敏感用户信息
安装使用bcrypt库:pip install bcrypt
生成一个固定的Salt
image.png
复制生成的固定的bin类型值(每次都不一样)
#user.py
from bcrypt import hashpw
SALT = b'$2b$10$8g62hrrYx4W11cQTuvi5ye'
def password_crypt(password):
password = password.encode()
cry_pwd = hashpw(password, SALT)
return cry_pwd.decode()
增加写入用户函数
def write_user(username, password):
fob = open('./userinfo.txt', 'a', encoding = 'utf-8')
fob.write(username + '=>' + password_crypt(password) + '\n')
fob.close()
return True
全部的user.py
import os
from bcrypt import hashpw
SALT = b'$2b$10$8g62hrrYx4W11cQTuvi5ye'
if not os.path.exists('./userinfo.txt'):
open('./userinfo.txt', 'w', encoding = 'utf-8').close()
def password_crypt(password):
password = password.encode()
cry_pwd = hashpw(password, SALT)
return cry_pwd.decode()
def read_user(username, password, nopwd = False):
userinfo = dict()
with open('./userinfo.txt', 'r', encoding = 'utf-8') as fob:
for line in fob.readlines():
uname = line.strip().split('=>')[0]
try:
pwd = line.strip().split('=>')[1]
userinfo[uname] = pwd
except:
print('\033[1;31;40m 严重:用户信息文件格式错误,系统无法运行 \033[0m')
exit(1)
if nopwd == True:
if username in userinfo:
return False
else:
return True
if userinfo.get(username,False) == password:
return True
return False
def write_user(username, password):
fob = open('./userinfo.txt', 'a', encoding = 'utf-8')
fob.write(username + '=>' + password_crypt(password) + '\n')
fob.close()
return True
修改main.py增加注册功能
from bottle import run,route,template,request,response
from user import read_user
from user import write_user
from user import password_crypt
@route('/login', method = 'GET')
def login_get():
username = request.get_cookie('username', secret = 'usafe')
password = request.get_cookie('password', secret = 'psafe')
if read_user(username, password):
return '你已经登录'
return template('login')
@route('/login', method = 'POST')
def login_post():
username = request.forms.get('username')
password = request.forms.get('password')
password = password_crypt(password)
if read_user(username, password):
response.set_cookie('username', username, secret = 'usafe', httponly = True, max_age = 600)
response.set_cookie('password', password, secret = 'psafe', httponly = True, max_age = 600)
return '登录成功'
return '账号密码错误'
@route('/register', method = 'GET')
def register_get():
return template('register')
@route('/register', method = 'POST')
def register_post():
username = request.forms.get('username')
password = request.forms.get('password')
if read_user(username, password, nopwd = True):
write_user(username, password)
return 'success'
return 'register faild'
run(host = 'localhost', port = 80, debug = True, reloader = True)
用户注册后生成的密码:
image.png
cookie中的密码:
image.png
下一步我们把用户的post数据在浏览器加密,然后后端再做一次加密,实际部署中,建议使用HTTPS证书
作者:firewt
链接:https://www.jianshu.com/p/27cf9f06288d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。