项目 03 用户登录与注册
需要导入 redis和 packet
pip install redis
pip install packet
app.py 用于保存用户登录信息的cookie设置
import os import tornado.ioloop import tornado.options import tornado.web from tornado.options import define,options from handlers import main,auth define('port',default='8000',help='Listening port',type=int) class Application(tornado.web.Application): def __init__(self): handlers = [ ('/',main.IndexHandler), ('/explore', main.ExploreHandler), ('/post/(?P<post_id>[0-9]+)', main.PostHandler), ('/upload', main.UploadHandler), ('/login', auth.LoginHandler), ('/logout', auth.LogoutHandler), ('/signup', auth.SignupHandler), ] settings = dict( debug = True, template_path = 'templates', static_path = os.path.join(os.path.dirname(__file__),'static'), login_url = '/login',#要让必须登录之后才能访问首页 cookie_secret = '95815451dasdwa1',#加密cookie的字符串 pycket = { #固定写法packet,用于保存用户登录信息 'engine':'redis', 'storage':{ 'host':'localhost', 'port':6379, # 'password':'' 'db_sessions':5, 'db_notifications':11, 'max_connections':2 ** 30 }, 'cookie':{ 'expires_days':30, }, } ) super(Application,self).__init__(handlers,**settings) application = Application() if __name__ == '__main__': tornado.options.parse_command_line() application.listen(options.port) print("Server start on port {}".format(str(options.port))) tornado.ioloop.IOLoop.current().start()
templates/base.html 模板页面更新,添加登出按钮,更改样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}Tornado Title {% end %}</title> </head> <body> <div style="width: 200px;height: 100px;display: block;"> <a href="/logout">登出</a> </div> <div style="width: auto; text-align:center"> {% block content %} base content {% end %} </div> </body> </html>
handlers/main.py 主函数更新
import tornado.web import os from pycket.session import SessionMixin from utils import photo class AuthBaseHandler(tornado.web.RequestHandler,SessionMixin): def get_current_user(self): return self.session.get('tudo_user_info') #session是一种会话状态,跟数据库的session可能不一样 class IndexHandler(AuthBaseHandler): """ Home page for user,photo feeds """ @tornado.web.authenticated #要让首页必须登录之后才可以访问,用这个装饰器就可以,但是要在app.py里面设置login_url def get(self,*arg,**kwargs): images_path = os.path.join(self.settings.get('static_path'),'uploads') images = photo.get_images(images_path) self.render('index.html',images = images)
utils/account.py 专门放与用户相关的函数,比如判断用户密码是否匹配等等
''' 用户相关的函数 ''' import hashlib#系统自带的加密库 hash加密 USER_DATA = {#用于判断用户密码是否匹配 'name':'tudo', 'password':hashlib.md5('123qwe'.encode('utf8')).hexdigest(),#给密码加密,用hashlib来算法加密,utf8不加的话就是默认utf8 } def authenticate(username,password):#用户密码匹配判断函数 if username and password: hash_pw = hashlib.md5(password.encode()).hexdigest()#给输入的密码进行算法加密 if username == USER_DATA['name'] and hash_pw == USER_DATA['password']:#如果用户密码与数据库里面的用户密码匹配 return True return False
handlers/auth.py 用户登录认证
''' 此文件是专门针对认证的 ''' import tornado.web from utils.account import authenticate from .main import AuthBaseHandler class LoginHandler(AuthBaseHandler): #登录的路由 def get(self, *args, **kwargs): if self.current_user:#如果用户已经登录 self.redirect('/')#那么就直接跳转到主页 self.render('login.html') def post(self, *args, **kwargs): username = self.get_argument('username',None) #获取用户 password = self.get_argument('password',None) #获取密码 passed = authenticate(username,password)#调用用户密码校验函数 if passed: self.session.set('tudo_user_info',username)#将前面设置的cookie设置为username,保存用户登录信息 self.redirect('/') #跳转主页路由 else: self.write({'msg':'login fail'})#不通过,有问题 class LogoutHandler(AuthBaseHandler):#登出的路由 def get(self): self.session.set('tudo_user_info','')#将用户的cookie清除 self.redirect('/login')#返回登录路由 class SignupHandler(AuthBaseHandler):#注册的路由 def get(self,*args,**kwargs): self.render('signup.html') def post(self): username = self.get_argument('username','') email = self.get_argument('email','') password1 = self.get_argument('password1','') password2 = self.get_argument('password2','') if username and password1 and password2: if password1 != password2: self.write({'mfg':'两次输入的密码不同'}) else: pass
templates/login.html 登录页面
{% extends 'base.html' %} {% block title %} login page {% end %} {% block content %} <div class=""> <div class=""> <form action="/login?next={{ '/' }}" method="post" enctype="multipart/form-data">#依次是发送表单数据的路由,发送表单数据的函数,和固定写法 <div class="form-group"> Username <input autofocus="" class="form-control" id="id_username" maxlength="254" name="username" type="text" required=""> </div> <div class="form-group"> Password <input class="from-control" id="id_password" name="password" type="password" required=""> </div> <button class="">Login</button> <div> 还没有账号,需要 <a href="/signup">注册</a>一个 </div> </form> </div> </div> {% end %}
templates/signup.html 注册页面
{% extends 'base.html' %} {% block title %} tagram page {% end %} {% block content %} <div class=""> <form action="/signup/" method="post" enctype="multipart/form-data"> <div class="form-group"> Username <input autofocus="" class="form-control" id="id_username" maxlength="150" name="username" type="text" required=""> </div> <div class="form-group"> Email <input class="form-control" id="id_email" name="email" type="email" required=""> </div> <div class="form-group"> Password <input class="from-control" id="id_password1" name="password1" type="password" required=""> </div> <div class="form-group"> Password confirmation <input class="from-control" id="id_password2" name="password2" type="password" required=""> </div> <button class="btn btn-default">注册</button> <div class="text-canter help-text"> 已有账号请 <a href="/login">登录</a> </div> </form> </div> {% end %}