热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python实现简单用户认证和角色制授权

实验目的了解BRAC原理基于Tornado框架,编写简单认证与授权程序实验素材python2.7.x或python3.4.x

实验目的

  1. 了解 BRAC 原理
  2. 基于 Tornado 框架,编写简单认证与授权程序

实验素材

  1. python 2.7.x 或 python 3.4.x
  2. tornado 4.2.x
  3. Sublime 或 Vim 或 Emacs 等编辑器,也可以使用 pyscript 或 pycharm 等集成环境(IDE)
  4. Tornado 官方 文档 ,参考中文 文档
  5. Tornado 自学 教程 ,作者的 博客
  6. curl 工具 官网
  7. mongodb & pymongo

任务 1:实现简单用户认证

  1. 阅读 自学教程 6.3 了解用户认证; 教程 4.1 和 4.2 了解 mongodb 使用。 也可以使用 tornado 推荐的方法引入数据库连接 RequestHandler.initialize。
  2. 在 mongodb 中建立 user文档,必须包含 identity, alias name, password 三个属性。其中 password 的内容用 MD5 加密。
  3. 修改程序 COOKIEs.py, 另存为 sample_auth.py , 该程序能够数据库实现用户认证。

注:教程上的缺陷:教程在 application 类中初始化了 mongodb 的连接,这等于默认应用运行于单线程之下。实战中, 建议每次使用前连接。 不用担心连接开销, 驱动一般内置 缓冲池 管理的。

任务 2:实现按角色授权

  1. 修改 sample_auth.py 为 auth.py 。 该程序支持 admins, users, vips, guests 四种角色。 匿名用户默认属于 guests, 登录用户默认 属于 users。
  2. auth.py 至少有四个页面,支持不同角色的服务。 请修改 mongodb ,加入合适的数据。
  3. 为了方便设置权限, 请实现装饰器 @roles(rolelist),例如, @role([‘vips’,’user’]) 表示vip和普通用户都可以访问的url, 其他用户转没有权限网页

任务1步骤如下:

  1. 了解教程中的用户认证方式;
  2. 学会如何向mongodb中添加数据和建立文档, 编写如下的python脚本将测试建立user文档并向其中输入一组测试数据
    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,如下:

  3. 修改教程所给代码如下
    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”,并输入测试数据,就可以了。

  4. 这个实验主要是学会使用python 操作mongodb并体验下利用数据库和装饰器来进行用户认证

任务二:

  1. 首先要理解和编写装饰类,了解其中的原理:除了实验中所说的,还可以看看http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000;主要是要明白装饰类是用来增强原先的函数的,更加本质上其实是修改了原本的函数指针,但没有改变它的运行上下文,也就是可以访问原先函数可以访问的,比如self,理解这个很重要,也正是因为这个原因,所以装饰器@tornado.web.authenticated才可以进行验证self.current_user是否存在。
  2. 根据实验需要编写如下的python脚本建立文档和导入测试数据
    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 }}

    View Code
    
    "en">
    
    
        "UTF-8">
        
    
    
    
        

    Welcome back, Guest

    View Code
    
    "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"/>
    View Code
    
    "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"/>
    View Code
    
    "en">
    
    
        "UTF-8">
        
    
    
    
        

    Permission denied

    View Code
    
    "en">
    
    
        "UTF-8">
        
    
    
    
    

    Welcome back,{{ role }} • {{ user }}

    View Code
    
    "en">
    
    
        "UTF-8">
        
    
    
    
    

    Welcome back,{{ role }} • {{ user }}

    View Code

    虽然里面几个文件的内容都是一样的,但只是为了方便,实验中主要是为了进行测试,不同的角色能够访问的网页是不同的。

  3. 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()
    View Code

    以上是程序运行的程序,@role装饰类主要是用于根据访问者的角色判断其是否可以进行访问当前的网页。大体的测试思路是:

    • 运行程序 createDB.py建立文档

    • 运行程序 python auth.py
    • 访问localhost:8000/login,选择输入用户信息或者是匿名登录
    • 进入相应的主页,若不是匿名登录会统一来到index.html的主页,通过在这个主页中选择相应的网页,如果角色符合就可以进行访问,否则会被拒绝

附加:关于COOKIE的,当客户端第一次登录网页并填写信息时,服务器会产生一个COOKIE(也就是程序中的set_security_COOKIE),而且在这个COOKIE会连同响应报文一起发给客户端;之后客户端再登录时,就可以通过这个COOKIE直接通过@tornado.web.authenticated的认证,所以就可以直接进入到只有一定权限才能访问的网页了。比如我们一开始没有COOKIE时,是访问不了localhost:8000/(这个只有登录的非匿名用户才可以访问),但是我们第一次登录后,获取COOKIE并在这个COOKIE的有效期内我们就可以不用再登录(输入用户名和密码)而直接进入localhost:8000/了。

 


推荐阅读
  • Hyper Text Coffee Pot Control Protocol
    The ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Pycharm编辑器取消双击shift弹出搜索框的方法
    在使用Pycharm编辑器时,双击shift会弹出搜索框界面,导致输入失去焦点,给用户带来不便。本文介绍了取消双击shift弹出搜索框的方法:在Pycharm中双击shift,输入registry并回车,找到“ide.suppress.double.click.handler”并勾选后,关闭即可解决该问题。通过这个方法,你再也不会被shift问题困扰了。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • HTML学习02 图像标签的使用和属性
    本文介绍了HTML中图像标签的使用和属性,包括定义图像、定义图像地图、使用源属性和替换文本属性。同时提供了相关实例和注意事项,帮助读者更好地理解和应用图像标签。 ... [详细]
  • 本文介绍了MongoDB中的覆盖索引查询(Covered Queries)的概念和使用方法。当查询的查询条件和查询计划中只包含索引属性时,MongoDB可以高效地执行查询操作,无需扫描documents或者将documents调入内存中。覆盖索引查询的条件是查询中的所有属性都是索引的一部分,并且查询结果中的属性值都在同一个索引中。通过使用覆盖索引查询,MongoDB可以直接从RAM中的索引中获取数据,比通过扫描文档读取数据要快得多。本文还提供了一个使用覆盖索引查询的示例。 ... [详细]
  • 本文介绍了如何使用vue-awesome-swiper组件,包括在main.js中引入和使用swiper和swiperSlide组件,以及设置options和ref属性。同时还介绍了如何在模板中使用swiper和swiperSlide组件,并展示了如何通过循环渲染swipes数组中的数据,并使用picUrl属性显示图片。最后还介绍了如何添加分页器。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • ZABBIX 3.0 配置监控NGINX性能【OK】
    1.在agent端查看配置:nginx-V查看编辑时是否加入状态监控模块:--with-http_stub_status_module--with-http_gzip_stat ... [详细]
  • php7 curl_init(),php7.3curl_init获取301、302跳转后的数据
    最近在做一个蜘蛛项目,发现在抓取数据时,有时会碰到301的页面,原本写的curl_init函数php7-远程获取api接口或网页内容&#x ... [详细]
author-avatar
杀手也热血_949
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有