zoukankan      html  css  js  c++  java
  • tornado

    xsrf_token认证 -- 防止CSRF

    可以通过一个Cookie和一个隐藏的HTML表单元素向页面提供令牌。这样,当一个合法页面的表单被提交时,它将包括表单值和以存储的Cookie。如何两者匹配,则Tornado应用认定请求有效。

    开启CSRF防范功能需要两个步骤:

    1.实例化的时候传入 "xsrf_cookies": True 参数。

    settings={
    'template_path':'templates',#配置模板路径
    'static_path':'static',     #配置静态文件存放的路径
    'static_url_prefix':'/zhanggen/', #在模板中引用静态文件路径时使用的别名 注意是模板引用时的别名
    "xsrf_cookies": True,           #使用xsrf认证
    }
    

    2.在有表单的模板文件中,为所有表单条件 xsrf_form_html()函数标签。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href='{{static_url("dist/css/bootstrap.css") }}'>
        <title>Title</title>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-5 col-md-offset-3">
                <form method="post" >
                    {% raw xsrf_form_html() %}
                      <div class="form-group">
                        <input type="text" class="form-control" placeholder="用户名" name="user">
                      </div>
                      <div class="form-group">
                        <input type="password" class="form-control" placeholder="密码" name="pwd">
                      </div>
                      <button type="submit" class="btn btn-default">提交</button>
                </form>
            </div>
        </div>
    </div>
    </body>
    </html>
    

    {% raw xsrf_form_html() %}起到了为表单添加隐藏元素以防止跨站请求的左右。

    cookie读写

    tornado不自动session,但是包含cookie

    Cookie是很多网站辨别用户的身份而存储在用户本地终端(client Side)的数据。在Tornado中使用self.get_cookie()self.set_cookie()可以方便的对Cookie进行读写。

    import tornado.web
    
    session_id = 1
    
    class MainHandler(tornado.web.RequestHandler):
        
        def get(self):
            if not self.get_cookie("session"):
                t = time.time()+10
                self.set_cookie("session", str(session_id), expires=t) 	# 并且设置了过期时间       
                self.write("设置了一个新的session!")
            else:
                self.write("session已存在!")
    

    在实际应用中,cookie经常用于保存session的信息。

    可以设置在用户不断刷新页面的情况下,cookie不过期。

    构造initialize方法:

    import tornado.web
    
    session_id = 1
    
    class MainHandler(tornado.web.RequestHandler):
        
        def initialize(self):
            if not self.get_cookie("session"):
                t = time.time()+10
                self.set_cookie("session", str(session_id), expires=t) 	# 并且设置了过期时间       
                self.write("设置了一个新的session!")
            else:
                self.write("session已存在!")
    

    cookie加密

    因为cookie总数被保存在客户端,所有如何保证不被篡改是服务器端程序必须解决的问题。Tornado提供了为cookie信息加密的机制,使得客户端无法随意解析和修改cookie的键值。

    在初始化时传入'cookie_secret' :'xsseffekrjewkhwy' 做cokies加密时使用的密钥,不能泄露出去。

    get_secute_cookie替换get_cookie, 用set_secure_cookie替换set_cookie,这样就不需要担心cookie伪造的问题了。

    import tornado.web
    import tornado.ioloop
    
    settings={
    		"xsrf_cookies": True, 
            'cookie_secret':'xsseffekrjewkhwy'  # 配置加密cookie使用得加密字符串
        }
    
    session_id = 1
    
    class MainHandler(tornado.web.RequestHandler):
        
        def get(self):
            if not self.get_secute_cookie("session"):
                t = time.time()+10
                self.set_secure_cookie("session", str(session_id), expires=t) 	# 并且设置了过期时间       
                self.write("设置了一个新的session!")
            else:
                self.write("session已存在!")
                
    app = tornado.web.Application([
        (r"/", MainHandler)],
        **settings
    )
    
    if __name__ == "__main__":
        
        app.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    

    @authenticated 用户认证

    在RequestHandler类中有一个current_user属性用于保存当前请求的用户名,默认值是None,在get()、post()等处理函数中可以随时读取该属性可以获得当前的用户名。

    需要重写get_current_user()方法来设置该属性值。

    基本框架代码:

    import tornado.web
    import tornado.ioloop
    
    class BaseHandler(tornado.web.RequestHandler):
        # 基类,重写get_current_user方法
        def get_current_user(self):
            
            return self.get_secure_cookie("session_id")
        
    class MainHandler(BaseHandler):
        
        @tornado.web.authenticated	# 能够检测用户是否登录
        def get(self):
            name = tornado.escape.xhtml_escape(self.current_user)
            self.write("Hello, " + name)
            
    class LoginHandler(BaseHandler):
        
        def get(self):
            self.render("login.html")
        
        def post(self):
            name = self.get_argument("user")
            self.set_secure_cookie("session_id", name)
            self.redirect("/")
            
    settings={
            'template_path':'templates',
            'static_path': 'static',
            'static_url_prefix':'/static/', 
            'cookie_secret':'sssseertdfcvcvd'
            'login_url':'/login'    # @authenticated 验证失败跳转的url
        }
                
    app = tornado.web.Application([
        (r"/", MainHandler),
    	(r"/login", LoginHandler)],
        **settings
    )
    
    if __name__ == "__main__":   
        app.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
        
    

    框架解读:

    上面是一个较完整的身份认证框架(可完善:用户session保存数据库,密码验证机制等。):

    • 定义公共基类BaseHandler,继承tornado.web.RequestHandler,用于动议本网站所有处理器的公共属性和方法。重构get_current_user()方法,获取并返回本次访问的会话ID。
    • MainHandler类是一个要求用户经过身份认证才能访问的视图。 get()方法使用了装饰器tornado.web.authenticated,说明在执行该方法之前需要根据current_user是否有值来判断用户的身份认证情况。如果有值则可以进行正常逻辑,否则自动重定向到登录页面(login_url的配置)。
    • LoginHandler是登录逻辑的视图,get()用于渲染登录页面,post()用于用户登录验证。
    • settings中的login_url 参数是定义网站的登录页面地址。当tornado.web.authenticated 发现用户尚未认证时,重定向到定义的URL。

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href='{{static_url("dist/css/bootstrap.css") }}'>
        <title>Title</title>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-5 col-md-offset-3">
                <form method="post" >
                    {% raw xsrf_form_html() %}
                      <div class="form-group">
                        <input type="text" class="form-control" placeholder="用户名" name="user">
                      </div>
                      <div class="form-group">
                        <input type="password" class="form-control" placeholder="密码" name="pwd">
                      </div>
                      <button type="submit" class="btn btn-default">提交</button>
                </form>
            </div>
        </div>
    </div>
    </body>
    </html>
    
  • 相关阅读:
    Rancher2.x部署K8s
    windows 安装 rabbitmq
    Mysql优化
    Docker部署Nginx应用(2)
    Docker入门笔记(1)
    kafka的安装及基本使用
    Dubbo的Api+Provider+Customer示例(IDEA+Maven+Springboot+dubbo)
    zookeeper 数据节点的增删改查
    zookeeper伪分布集群配置
    密集重建
  • 原文地址:https://www.cnblogs.com/yzm1017/p/13570764.html
Copyright © 2011-2022 走看看