cookie、session登錄驗證csrf


 

cookie

在上節課,我們簡單了解了登錄過程,但是很明顯,每次都需要登錄,但是在平常逛網站的只需要登錄一次,那么網站是如何記錄登錄信息的呢?

有沒有什么辦法可以讓瀏覽器記住登錄信息,下次再次打開的時候,可以自動登錄呢?

設置cookie與獲取cookie

import sys
import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler
from tornado.options import define,options
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User

define('port',default=8080,help='run server',type=int)
class MainHandler(RequestHandler):
    def get(self):
        self.write('cookie')
        self.set_cookie('cookie_test','aqweqwas')
        self.set_cookie('cookie_test2','aqweqwas2',expires=time.time()+60)  #設置過期時間
        self.set_cookie('cookie_test3','aqweqwas3',expires_days=1)  #設置過期天數
        self.set_cookie('cookie_test4','aqweqwas4',path='/')  #設置cookie路徑
        self.set_cookie('cookie_test5','aqweqwas5',httponly=True)  #設置后js代碼獲取不到此cookie值
        self.set_cookie('cookie_test6','aqweqwas6',max_age=120,expires=time.time()+60)  #設置過期時間max_age的優先級大於expires
        self.set_secure_cookie('cookie_test7','aqweqwas7',max_age=120,expires=time.time()+60)  #設置加密cookies

class GetHandler(RequestHandler):
    def get(self):
        self.write('get_cookie')
        self.write('<br>')
        cookie_name = self.get_cookie('cookie_test4')
        cookie_name2 = self.get_secure_cookie('cookie_test7')

        self.write(cookie_name)
        self.write('<br>')
        self.write(cookie_name2)
application = tornado.web.Application(
    handlers=[
        (r'/',MainHandler),
        (r'/get',GetHandler),
    ],
    debug=True,
    template_path = 'templates',
    static_path='static',
    # autoescape = None, #全局取消轉義
    ui_methods=util.ui_methods,
    ui_modules=util.ui_modules,
    cookie_secret ='qwe123', #cookie加鹽
)
if __name__ == '__main__':
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

登錄驗證:

第一步:導入裝飾器

from tornado.web import authenticated

第二步:聲明 BaseHandler

class BaseHandler(RequestHandler):
    def get_current_user(self):
        current_user = self.get_secure_cookie('user_ID')
        if current_user:
            return current_user
        return None

第三步:配置登錄路由

    login_url = '/login'

第四步:裝飾需要驗證的請求

class BuyHandler(BaseHandler):
    @authenticated
    def get(self):
        self.write('嗨,小可愛!')

在完成登錄之后,再來看看,我們從一個路由跳轉到登錄頁面之后,再完成登錄之后,該如何跳轉到之前的頁面呢?

第一步:獲取之前路由

class LoginHandler(BaseHandler):
    def get(self):
        next_name = self.get_argument('next','')
        self.render('in_out.html',nextname=next_name)

在使用 authenticated 之后,如果驗證不成功,會自動跳轉到登錄路由,並且在 URL 后面加上 next 參數,next 參數的參數值就是之前的路由

第二步:修改模板文件

    <form method="post" action="/login?next={{ nextname }}">

在模板中添加 next 參數,並且參數值為之前的路由

第三步:修改post方法

    def post(self):
        '''驗證邏輯'''
        user = self.get_argument('name',None)
        password = self.get_argument('password',None)
        next_name = self.get_argument('next','')
        print(next_name)
        # username = session.query(User).filter(User.username == user).first()
        username = User.get_name(user)
        print(username)
        if username and  password == username.password:
            #如果判斷用戶可以登錄,我們設置這樣一個加密的cookie進去
            self.set_secure_cookie('user_ID',user)
            self.redirect(next_name)
        else:
            self.write('登錄失敗')

獲取之前的頁面的路由

當登錄驗證通過之后,設置加密的 cookie ,並跳轉到之前的路由

完整的python代碼與模板html代碼如下:

import sys

import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler,authenticated
from tornado.options import define,options
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User

define('port',default=8080,help='run server',type=int)

class BaseHandler(RequestHandler):
    def get_current_user(self):
        current_user = self.get_secure_cookie('user_ID')
        if current_user:
            return current_user
        return None

class BuyHandler(BaseHandler):
    @authenticated
    def get(self):
        self.write('嗨,小可愛!')
        #第一,如果有參數next,肯定是沒登錄的時候
        #沒登錄,會跳轉到/login,app里面設置的
        #在login里面,form表單沒提交之前,get里面獲取一下這個值
        #在獲取出來之后,吧這個值傳到post請求里面
        #post獲取這個值,此值就是一個url
        #直接跳轉到此url


class LoginHandler(BaseHandler):
    def get(self):
        next_name = self.get_argument('next','')
        self.render('in_out.html',nextname=next_name)

    def post(self):
        '''驗證邏輯'''
        user = self.get_argument('name',None)
        password = self.get_argument('password',None)
        next_name = self.get_argument('next','')
        print(next_name)
        # username = session.query(User).filter(User.username == user).first()
        username = User.get_name(user)
        print(username)
        if username and  password == username.password:
            #如果判斷用戶可以登錄,我們設置這樣一個加密的cookie進去
            self.set_secure_cookie('user_ID',user)
            self.redirect(next_name)
        else:
            self.write('登錄失敗')


application = tornado.web.Application(
    handlers=[
        (r'/buy',BuyHandler),
        (r'/login',LoginHandler),

    ],
    debug=True,
    template_path = 'templates',
    static_path='static',
    # autoescape = None, #全局取消轉義
    ui_methods=util.ui_methods,
    ui_modules=util.ui_modules,
    cookie_secret ='qwe123', #cookie加鹽
    login_url = '/login'
)
if __name__ == '__main__':
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

in_out.html代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tornado</title>
</head>
<body>
    <form method="post" action="/login?next={{ nextname }}">
        <p>用戶名<input type="text" name="name"></p>
        <p>密碼<input type="password" name="password"></p>
        <input type="submit">
    </form>
</body>
</html>

 session

通過剛才的學習,可以用了解到 cookie 中的信息可以用來保存用戶的登錄信息,但是coolkie 是很容易被攔截的,所有其中必定不能有用戶的任何私密信息,那么又有什么辦法可以讓服務器保存用戶的登錄信息,但是cookie中又不會有用戶的任何信息呢?

第一步:安裝模塊

pip install pycket  #tornado中用於連接redis的模塊
pip install redis

第二步:導入模塊

from pycket.session import SessionMixin

第三步:繼承SessionMixin

class BaseHandler(tornado.web.RequestHandler, SessionMixin):

第四步:在application 中添加配置

配置 redis 的相關信息

配置 cookie 的過期時間

    pycket = {
        'engine':'redis',
        'storage':{
            'host':'localhost',
            'port':6379,
            'db_sessions':5,
            'max_connections':2**10,
        },
        'cookies':{
            'expires_days':7
        }
    }

第五步:改設置cookie為設置session

self.session.set('user_ID',user)

第六步:改獲取cookie為獲取session

current_user = self.session.get('user_ID')

完整代碼如下:

import sys

import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler,authenticated
from tornado.options import define,options
from pycket.session import SessionMixin
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User

define('port',default=8080,help='run server',type=int)

class BaseHandler(RequestHandler,SessionMixin):
    def get_current_user(self):
        current_user = self.session.get('user_ID')
        if current_user:
            return current_user
        return None

class BuyHandler(BaseHandler):
    @authenticated
    def get(self):
        self.write('嗨,小可愛!')
        #第一,如果有參數next,肯定是沒登錄的時候
        #沒登錄,會跳轉到/login,app里面設置的
        #在login里面,form表單沒提交之前,get里面獲取一下這個值
        #在獲取出來之后,吧這個值傳到post請求里面
        #post獲取這個值,此值就是一個url
        #直接跳轉到此url


class LoginHandler(BaseHandler):
    def get(self):
        next_name = self.get_argument('next','')
        self.render('in_out.html',nextname=next_name)

    def post(self):
        '''驗證邏輯'''
        user = self.get_argument('name',None)
        password = self.get_argument('password',None)
        next_name = self.get_argument('next','')
        print(next_name)
        # username = session.query(User).filter(User.username == user).first()
        username = User.get_name(user)
        print(username)
        if username and  password == username.password:
            #如果判斷用戶可以登錄,我們設置這樣一個加密的cookie進去
            # self.set_secure_cookie('user_ID',user)
            self.session.set('user_ID',user)
            self.redirect(next_name)
        else:
            self.write('登錄失敗')


application = tornado.web.Application(
    handlers=[
        (r'/buy',BuyHandler),
        (r'/login',LoginHandler),

    ],
    debug=True,
    template_path = 'templates',
    static_path='static',
    # autoescape = None, #全局取消轉義
    ui_methods=util.ui_methods,
    ui_modules=util.ui_modules,
    cookie_secret ='qwe123', #cookie加鹽
    login_url = '/login',
    pycket = {
        'engine':'redis',
        'storage':{
            'host':'localhost',
            'port':6379,
            'db_sessions':5,
            'max_connections':2**10,
        },
        'cookies':{
            'expires_days':7
        }
    }
)
if __name__ == '__main__':
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

XSRF:防止跨域請求偽造

使用session可以保證用戶信息不被cookie泄漏,那如果如果攻擊者不想獲取用戶信息,只是在提交 form 表單時攻擊,該怎么防范呢?

模板添加

{% module xsrf_form_html() %}

代碼如下:

<body>
    {% module xsrf_form_html() %}
    <form method="post" action="/login?next={{ nextname }}">
        <p>用戶名<input type="text" name="name"></p>
        <p>密碼<input type="password" name="password"></p>
        <input type="submit">
    </form>
</body>

Tornado 有內建的 XSRF 的防范機制,要使用此機制,只需要在模板中添加如上代碼

頁面效果顯示:

生成一段關於xsrf的隨機字符串,防止偽造


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM