注:教程上的缺陷:教程在 application 类中初始化了 mongodb 的连接,这等于默认应用运行于单线程之下。实战中, 建议每次使用前连接。 不用担心连接开销, 驱动一般内置 缓冲池 管理的。
任务1步骤如下:
import hashlib from pymongo import MongoClient def createDB(): client = MongoClient("127.0.0.1", 27017) db = client["privace"] user = db.user #md5 m1 = hashlib.md5() m1.update("user") password = m1.hexdigest() user.insert({"identity":"user", "alias name": "user", "password": password}) def createAll(): client = MongoClient("127.0.0.1", 27017) db = client["privace"] user = db.user user.remove(); if __name__ == '__main__': createAll() createDB()
在终端中进行脚本运行并查看mongodb,如下:
import tornado.httpserver import tornado.ioloop import tornado.web import tornado.options import os.path import hashlib from pymongo import MongoClient from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_COOKIE("aliasName") class LoginHandler(BaseHandler): def get(self): self.render("login.html") def post(self): #self.set_secure_COOKIE("username", self.get_argument("username")) identity = self.get_argument("identity") #aliasName = self.get_argument("alias") password = self.get_argument("password") #md5 md5Password = hashlib.md5() md5Password.update(password) password = md5Password.hexdigest() print password client = MongoClient("127.0.0.1", 27017) self.db = client["privace"] userInfo = self.db.user user = userInfo.find_one({"identity": identity}) print "user"+str(user) if user: if password == user["password"]: self.set_secure_COOKIE("aliasName", user["alias name"]) #store the salias Name thrount COOKIE #print self.aliasName self.redirect("/") else: self.redirect("/login") else: self.redirect("/login") class WelcomeHandler(BaseHandler): @tornado.web.authenticated def get(self): self.render("index.html", user=self.current_user) class LogoutHandler(BaseHandler): def get(self): if(self.get_argument("logout", None)): #self.clear_COOKIE("username") self.redirect("/") if __name__ == '__main__': tornado.options.parse_command_line() settings = { "template_path": os.path.join(os.path.dirname(__file__), "templates"), "COOKIE_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "xsrf_COOKIEs": True, #http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html ;event the attacker "get" the COOKIEt, but the xsrf_COOKIEs is safe. the attacker cann't make the false request(form) "login_url":"/login" } application = tornado.web.Application([ (r'/', WelcomeHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler) ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
在终端中输入命令"python sample_auth.py",启动服务器,此时便可以在浏览器中输入“localhost:8000/login”,并输入测试数据,就可以了。
任务二:
import hashlib from pymongo import MongoClient def createDB(): client = MongoClient("127.0.0.1", 27017) db = client["privace"] role = db.role #md5 m1 = hashlib.md5() m1.update("admin") password = m1.hexdigest() role.insert({"identity":"admin", "alias name": "admin", "password": password, "role": "admin"}) m1 = hashlib.md5() m1.update("user") password = m1.hexdigest() role.insert({"identity":"user", "alias name": "user", "password": password, "role": "user"}) m1 = hashlib.md5() m1.update("vip") password = m1.hexdigest() role.insert({"identity":"vip", "alias name": "vip", "password": password, "role": "vip"}) def createAll(): client = MongoClient("127.0.0.1", 27017) db = client["privace"] role = db.role role.remove(); if __name__ == '__main__': createAll() createDB()
同时也增加了如下的html文件(也位于templates中)
,{{ "en"> "UTF-8">Welcome back,{{ role }} • {{ user }}
"en"> "UTF-8">Welcome back, Guest
"en"> "UTF-8">Welcome back,{{ role }} • {{ user }}
"/" method="POST"> {% raw xsrf_form_html() %} "radio", name="role", value="user"> User
"radio", name="role", value="vip"> Vip
"radio", name="role", value="admin"> Admin
"submit" value="Log In"/>
"en"> "UTF-8"> "/login" method="POST"> {% raw xsrf_form_html() %} identity: "text" name="identity"/>
password: "text" name="password"/>
guest: "checkbox" name="guest" value="guest"/>Guest
"submit" value="Log In"/>
"en"> "UTF-8">Permission denied
"en"> "UTF-8">Welcome back,{{ role }} • {{ user }}
"en"> "UTF-8">Welcome back,{{ role }} • {{ user }}
虽然里面几个文件的内容都是一样的,但只是为了方便,实验中主要是为了进行测试,不同的角色能够访问的网页是不同的。
import tornado.httpserver import tornado.ioloop import tornado.web import tornado.options import os.path import hashlib import functools from pymongo import MongoClient from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) def role(roleList): def decorator(func): @functools.wraps(func) def wrapper(self, *args, **kw): identify = self.current_user client = MongoClient() db = client["privace"] roleSet = db.role person = roleSet.find_one({"identity": identify}) role = person["role"] if role in roleList: func(self) else: self.redirect("/permission") return wrapper return decorator class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_COOKIE("identity") #use self to get the identify and get the role class LoginHandler(BaseHandler): def get(self): self.render("login.html") def post(self): guest = self.get_argument("guest", None); if guest != None: self.redirect("/guest") return #self.set_secure_COOKIE("username", self.get_argument("username")) identity = self.get_argument("identity") #aliasName = self.get_argument("alias") password = self.get_argument("password") #md5 md5Password = hashlib.md5() md5Password.update(password) password = md5Password.hexdigest() client = MongoClient() self.db = client["privace"] role = self.db.role person = role.find_one({"identity": identity}) if person: if password == person["password"]: self.set_secure_COOKIE("identity", person["identity"]) #store the salias Name thrount COOKIE self.redirect("/") else: self.redirect("/login") else: self.redirect("/login") #only not for guest class WelcomeHandler(BaseHandler): @tornado.web.authenticated def get(self): client = MongoClient() self.db = client["privace"] role = self.db.role person=role.find_one({"identity": self.current_user}) self.render("index.html", user=self.current_user, role=person["role"]) def post(self): choice = self.get_argument("role"); print choice if choice == "user": self.redirect("/user") elif choice == "vip": self.redirect("/vip") elif choice == "admin": self.redirect("/admin") else: pass class WelcomeUserHandler(BaseHandler): @tornado.web.authenticated @role(['admin', 'vip', 'user']) def get(self): client = MongoClient() self.db = client["privace"] roleInfo = self.db.role person = roleInfo.find_one({"identity": self.current_user}) self.render("user.html", user=self.current_user, role=person["role"]) class WelcomeAdminHandler(BaseHandler): @tornado.web.authenticated @role(['admin']) def get(self): client = MongoClient() self.db = client["privace"] roleInfo = self.db.role person = roleInfo.find_one({"identity": self.current_user}) self.render("admin.html", user=self.current_user, role=person["role"]) class WelcomeVipHandler(BaseHandler): @tornado.web.authenticated @role(['vip']) def get(self): client = MongoClient() self.db = client["privace"] roleInfo = self.db.role person = roleInfo.find_one({"identity": self.current_user}) self.render("vip.html", user=self.current_user, role=person["role"]) class WelcomeGuestHandler(BaseHandler): @role(['guest']) def get(self): self.render("guest.html") class LogoutHandler(BaseHandler): def get(self): if(self.get_argument("logout", None)): self.clear_COOKIE("username") self.redirect("/") class PermissionHandler(BaseHandler): def get(self): self.render("permission.html") if __name__ == '__main__': tornado.options.parse_command_line() settings = { "template_path": os.path.join(os.path.dirname(__file__), "templates"), "COOKIE_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "xsrf_COOKIEs": True, #http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html ;event the attacker "get" the COOKIEt, but the xsrf_COOKIEs is safe. the attacker cann't make the false request(form) "login_url":"/login" } application = tornado.web.Application([ (r'/', WelcomeHandler), (r'/user', WelcomeUserHandler), (r'/admin', WelcomeAdminHandler), (r'/vip', WelcomeVipHandler), (r'/guest', WelcomeGuestHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler), (r'/permission', PermissionHandler) ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
以上是程序运行的程序,@role装饰类主要是用于根据访问者的角色判断其是否可以进行访问当前的网页。大体的测试思路是:
运行程序 createDB.py建立文档
附加:关于COOKIE的,当客户端第一次登录网页并填写信息时,服务器会产生一个COOKIE(也就是程序中的set_security_COOKIE),而且在这个COOKIE会连同响应报文一起发给客户端;之后客户端再登录时,就可以通过这个COOKIE直接通过@tornado.web.authenticated的认证,所以就可以直接进入到只有一定权限才能访问的网页了。比如我们一开始没有COOKIE时,是访问不了localhost:8000/(这个只有登录的非匿名用户才可以访问),但是我们第一次登录后,获取COOKIE并在这个COOKIE的有效期内我们就可以不用再登录(输入用户名和密码)而直接进入localhost:8000/了。