Tornado 用户注册&登录&登出(User regist&login&logout)

Tornado 用户注册&登录&登出(User regist&login&logout)

############################################

@Tornad 英文官网

@Tornado 用户认证(User authentication )示例文档

@Tornado 博客(blog)GitHub 示例代码

 

############################################

##############################################################

环境:

Python 3.6.5 (default, Jun 25 2018, 17:02:26)

tornado               6.0.3      
Tornado-MySQL         0.5.1

mysql  Ver 14.14 Distrib 5.6.36, for Linux (x86_64) using  EditLine wrapper

##############################################################

 

##################################################################

#HTML 效果图

HTML UserRegis

 

<!--tornado/template/base.html-->
<!DOCTYPE html>   
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <meta name="description" content="GotIT Manage Network Automatically">
    <meta name="keywords" content="GotIT">
    <meta name="author" content="GotIT Web Dev Team">
    <link rel="shortcut icon" href="/static/icon/favicon.ico" type="image/x-icon" />
    <script type="text/javascript" src="/static/js/jquery.min.js"></script>
    <!--Base模板里的title标签,如果有传入替代标签就用替代的,没有就用默认的-->
    <title>{% block title %}Please checkout your page-title!{% end %}</title>
</head>
<body>
<!--模板里的body标签,用于body标签代入替换-->
{% block body %}<p>Set up you body-block first!</p>{% end %}
<!--模板里的js标签,用于js标签代入替换-->
{% block js %}{% end %}
<!--模板里的css标签,用于css标签代入替换-->
{% block css %}{% end %}
</body>
</html>
<!--tornado/template/regis.html-->
{% extends "base.html"%}    <!--调用模板,把block标签的部分插入模板中-->
{% block title %}User Regis{% end %} //title
{% block body %} //body
<div id="container">
  <form action="/regis" method="post"> <!--注册Form
    <!--xsrf 参数,render模块会把生成的xsrf的html替换到这里,在提交Form时
    这个隐藏的xsrf信息用于Tornado服务端校验,以确保本次提交的Form信息未被黑客篡改。-->
    {% module xsrf_form_html() %} 
    <input name="uname" type="text" placeholder="uname" required> <!--input类型,输入值后 uname=xxx -->
    <input name="upass" type="password" placeholder="upass" required> <!--input类型,输入值后 upass=xxx -->
    <input name="umail" type="email" placeholder="umail" autocomplete>
    <input name="utell" type="text" placeholder="utell" autocomplete>
    <!--submit为html的提交类型,点击后会自动提交对应的表单Form(包含表单内的输入内容)-->
    <button type="submit">注册(Regist)</button>
  </form>
</div>
{% end %}

{% block js %}
<script>
</script>
{% end %}

{% block css %}    <!--插入到模板里的 css标签-->
<style>
body{    /*body是css的html标签选择器,这里对body标签进行文字颜色,背景颜色,对齐方式进行设定*/
    color:green; /*文字颜色绿色*/
    background-color:black; /*背景颜色黑色*/
    ext-align:center; /*文字中间对齐*/
}
#container{    /*#container 是css语言的id选择器*/
    width:128px; 
    height:256px;
    margin-top:64px;
    margin-left:auto;
    margin-right:auto;
}
input{
    width:128px;
    height:64px;
    margin-top:2px;
    border-bottom:dashed green;
    border-top:none;
    border-left:none;
    border-right:none;
    outline:none;
    color:green;
    background-color:black;
}
button{
    width:128px;
    height:32px;
    margin-top:8px;
    border:solid green;
    outline:none;
    color:green;
    background-color:black;
}
</style>
{% end %}
UserLogin
HTML  UserLogin
<!--tornado/template/login.html-->
{% extends "base.html" %} <!--扩展base模板,替换里面的标签部分-->
{% block title %}Login Page{% end %}
{% block body %}
<div id="container">
<form action="/login" method="post">
  {% module xsrf_form_html() %}
  <input name="uname" type="text" placeholder="uname" required>
  <input name="upass" type="password" placeholder="upass" required>
  <!--submit为html的提交类型,点击后会自动提交对应的表单-->
  <button type="submit">登入(LOGIN)</button>
  <!--onclick添加JS里的relocal()功能,this为传入这个HTML的button对象-->
  <button type="button" onclick="relocal(this)">注册(REGIS)</button>
</form>
{% end %}
{% block js %} <!--JS模板标签-->
<script>
function relocal(self){
    window.location.href= "/regis"; <!--button被点击后,页面跳转到/regist注册页面-->
}
</script>
{% end %}
{% block css %}<!--CSS模板标签-->
<style>
body{
    color:green;
    background-color:black;
    ext-align:center;
}
#container{
    width:128px;
    height:256px;
    margin-top:64px;
    margin-left:auto;
    margin-right:auto;
}
input{
    width:128px;
    height:64px;
    margin-top:2px;
    border-bottom:dashed green;
    border-top:none;
    border-left:none;
    border-right:none;
    outline:none;
    color:green;
    background-color:black;
}
button{
    width:128px;
    height:32px;
    margin-top:8px;
    border:solid green;
    outline:none;
    color:green;
    background-color:black;
}
</style>
{% end %}
Index&UserLogout
HTML  Index&UserLogout

 

 

<!--tornado/template/index.html-->
{% extends "base.html" %}
{% block title %}GotIT Now!{% end %}
{% block body %}
<h1>Hello {{uname}}, Welcome to GotIT's Main Page!</h1>
<form action="/logout" method="get"> <!--用户登出表单Form-->
<!--render模块会代入的xsrf隐藏HTML,提交表单时服务端校验用-->
  {% module xsrf_form_html() %} 
  <!--checkbox默认值value为空,当勾选时value为on即logout=on,服务端只要校验logout=on就可以判断是否要执行登出-->
  <input name="logout" type="checkbox"/>
  <!--submit为html的提交类型,点击后会自动提交对应的表单-->
  <input type="submit" value="Logout"/>
</form>

<!--websocket 测试区域-->
<div id="msgPanel"></div>
<textarea id="msgInput" row=20 placeholder="Message"></textarea>
<button type="button" onclick="send()">发送(Send)</button>
{% end %}

{% block js %}
<script>
var ws = new WebSocket("ws://192.168.159.133:1010/ws");
ws.onopen = function(e){
    console.log("ws 已连接!");
};

ws.onclose = function(e){
    console.log("ws 已关闭!");
};

function send(){
    var msg = $('#msgInput').val();
    sendMsg(msg);
    ws.onmessage = function(e){
        console.log(e.data);
        var msgHtml = "<div>" + e.data + "</div>";
        console.log(msgHtml);
        $("#msgPanel").append(msgHtml);
    };
};

function sendMsg(msg){
        ws.send(JSON.stringify({
            'type': 'message',
            'user': '{{ uname }}',
            'msg': msg,
        }));
     $('#msgInput').val('');
};

</script>
{% end %}

###################################################################

 

##########################

tornado/manage.py       #主程序文件 Tornado Web Server

from tornado.web import Application
from tornado import ioloop, gen
from tornado import options
from views import Home, UserLogin, UserLogout, UserRegis
from tornado.options import define ,options, parse_command_line
from ws import WSEcho


define('WEB_HOST', default='192.168.159.133', help='Web Listen address')
define('WEB_PORT', type=int, default=1010, help='Web Listen port')

#重写tornado.web.Application并初始化
class MyApp(Application):
    def __init__(self):
        #urls正则匹配对应的url,把匹配到的请求推送给对应的view视图接口
        urls = [
            (r'/index', Home),
            (r'/login', UserLogin),
            (r'/logout', UserLogout),
            (r'/regis', UserRegis),
            (r'/ws', WSEcho),
        ]
        #定义Tornado web App初始的设定
        settings = dict(
            static_path = 'static',    #静态文件路径
            template_path = 'template', #HTML模板文件路径
            cookie_secret = '#404@*#',  #cookie加密密码
            login_url = '/login',       #未认证用户跳转路径
            xsrf_cookies = True,        #启用xsrf防劫持
            debug=True,                 #启用debug,打印出debug信息
        )
        super(Application, self).__init__(urls, **settings) #初始化


if __name__ == "__main__":
    parse_command_line()
    app = MyApp()
    app.listen(options.WEB_PORT, options.WEB_HOST) #绑定IP及端口
    print(app.settings) #打印出当前设定信息
    ioloop.IOLoop.current().start()

tornado/views.py          #视图文件 对浏览器(Brower)的请求(Request)进行分类处理

from __future__ import print_function
from tornado.web import RequestHandler, hashlib
from tornado.websocket import WebSocketHandler as ws
from tornado.web import authenticated as authed
from tornado.gen import coroutine
from tornado_mysql import pools

#使用tornado_mysql建立mysql连接池
pools.DEBUG = True
POOL = pools.Pool(dict(host='192.168.159.133', port=3306, user='tornado', passwd='tornado_pass', db='Tornado'),
       max_idle_connections=2,max_recycle_sec=3)

#重写RequestHandler类,定义get_current_user功能,使能记录当前登录用户
#当用户登入后会写入一个Cookie [self.set_secure_cookie('uname', uname)]
#tornado的auth模块会调用get_current_user功能返回的cookie值,并记录此cookie值
#代表的用户为登录状态
class req(RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("uname")


class Home(req):
    #添加tornado的authenticated修饰,当用户为未认证状态时,跳转到settings定义好的
    #[login_url = '/login',] URL
    @authed
    async def get(self):
        uname = self.current_user.decode('utf-8') #获取当前已认证用户名
        #render模块把uname代入到template模板[index.html]中替换模板语句jinjia2
        #对应的变量{{uname}}
        return self.render("index.html", uname=uname) 
    async def post(self):
        return self.write('post')

    def delete(self):
        return self.write('delete')


#用户登入
class UserLogin(req):
    #异步处理客户端GET请求,加快处理请求速度。
    async def get(self):
        return self.render("login.html", title="User Login Form")
    #协程处理花费较长时间的数据库查询事件,不会block Tornado进程。
    @coroutine
    def post(self):
        uname = self.get_argument('uname')
        upass = self.get_argument('upass')
        text = uname + upass
        md5pass =  hashlib.md5(text.encode()).hexdigest()
        #使用Tornado-Mysql,yield异步处理数据库查询
        cur = yield POOL.execute("SELECT password FROM user WHERE name=(%s)", (uname,))
        r = cur.fetchone()
        cur.close()
        if r:
            password = r[0]
            if password == md5pass:
                self.set_secure_cookie('uname', uname)
                print(self.current_user)
                return self.redirect("/index")
            else:
                return self.redirect("/login")
        else:
            return self.redirect("/login")


class UserLogout(req):
    async def get(self):
        logout = self.get_argument('logout', None)
        if logout=='on':
            self.clear_cookie("uname")
        return self.redirect('/index')


class UserRegis(req):
    async def get(self):
        return self.render("regis.html")
    @coroutine
    def post(self):
        uname = self.get_argument('uname', None)
        upass = self.get_argument('upass', None)
        umail = self.get_argument('umail', None)
        utell = self.get_argument('utell', None)
        text = uname + upass
        md5pass =  hashlib.md5(text.encode()).hexdigest()
        cur = yield POOL.execute("INSERT INTO `user` (`id`, `name`, `password`, `email`, `tel`) VALUES (NULL, %s, %s, %s, %s)",(uname, md5pass, umail, utell,))
        cur.close()
        return self.redirect('/login')

tornado/mysqldb.py        #连接mysql数据库的文件

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker


HOSTNAME = '192.168.159.133'    #mysql服务器IP
PORT = '3306'                   #mysql服务端口
DATABASE = 'Tornado'            #数据库名称
USERNAME = 'tornado'            #数据库用户,需要提前到mysql添加
PASSWORD = 'tornado_pass'       #用户密码
URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(
    USERNAME,
    PASSWORD,
    HOSTNAME,
    PORT,
    DATABASE
)
engine = create_engine(URL)
Base = declarative_base(bind=engine)
Session = sessionmaker(engine)
session = Session()

tornado/model.py         #数据表的model文件,设计表格结构内容

  1. python 控制台中,model.create_db()创建数据库
  2. main函数运行时去检查数据库是否存在,不存在就 model.create_db()
from sqlalchemy import Column, Integer, String
from mysqldb import Base

#创建表
def create_db():
    Base.metadata.create_all()

#删除表
def drop_db():
    Base.metadata.drop_all()

#User表的类,定义每一列的属性
class User(Base):
    id = Column(Integer, primary_key=True, autoincrement=True) #id列每个表都有的自动增长列
    name = Column(String(16), primary_key=False, unique=True, nullable=False) #用户名
    password = Column(String(32), primary_key=False,unique=False, nullable=False) #密码
    email = Column(String(32), primary_key=False, unique=False, nullable=False) #邮箱
    tel = Column(String(16), primary_key=False, unique=False, nullable=False) #电话
    __tablename__ = 'user' #表名

tornado/ws.py        #Tornado Websocket consumer文件,处理ws&wss服务请求

from tornado.websocket import WebSocketHandler as ws


class WSEcho(ws):
    def open(self):
        print("WebSocket open")
    def on_message(self, message): #客户端向服务端发送msg后触发
        self.write_message(message) #广播回复msg
    def on_pong(self, data):
        print(data)
    def on_close(self):
        print("WebSocket closed")

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值