要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX。

  在进行接口开发之前,还有一个重要的事情要处理,那就是对站点进行初始化,如果不进行初始化,那么独立文件编写的接口将会找不到,要将异常错误写入日志文件也会找不到路径,下面先上代码。

  打开main.py文件,改为下面代码(大家可以比较一下和之前代码有什么不同)

  1 #!/usr/bin/evn python2 # coding=utf-83 4 import bottle5 import sys6 import os7 import logging8 import urllib.parse9 from bottle import default_app, get, run, request, hook10 from beaker.middleware import SessionMiddleware11 12 # 导入工具函数包13 from common import web_helper, log_helper14 # 导入api代码模块(初始化api文件夹里的各个访问路由,这一句不能删除,删除后将无法访问api文件夹里的各个接口)15 import api16 17 #############################################18 # 初始化bottle框架相关参数19 #############################################20 # 获取当前main.py文件所在服务器的绝对路径21 program_path = os.path.split(os.path.realpath(__file__))[0]22 # 将路径添加到python环境变量中23 sys.path.append(program_path)24 # 让提交数据最大改为2M(如果想上传更多的文件,可以在这里进行修改)25 bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 226 27 #############################################28 # 初始化日志相关参数29 #############################################30 # 如果日志目录log文件夹不存在,则创建日志目录31 if not os.path.exists('log'):32     os.mkdir('log')33 # 初始化日志目录路径34 log_path = os.path.join(program_path, 'log')35 # 定义日志输出格式与路径36 logging.basicConfig(level=logging.INFO,37                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',38                     filename="%s/info.log" % log_path,39                     filemode='a')40 41 # 设置session参数42 session_opts = {43     'session.type': 'file',44     'session.cookie_expires': 3600,45     'session.data_dir': '/tmp/sessions/simple',46     'session.auto': True47 }48 49 50 @hook('before_request')51 def validate():52     """使用勾子处理接口访问事件"""53 54     # 获取当前访问的Url路径55     path_info = request.environ.get("PATH_INFO")56     # 过滤不用做任何操作的路由(即过滤不用进行判断是否登录和记录日志的url)57     if path_info in ['/favicon.ico', '/', '/api/verify/']:58         return59     ### 记录客户端提交的参数 ###60     # 获取当前访问url路径与ip61     request_log = 'url:' + path_info + ' ip:' + web_helper.get_ip()62     try:63         # 添加json方式提交的参数64         if request.json:65             request_log = request_log + ' params(json):' + urllib.parse.unquote(str(request.json))66     except:67         pass68     try:69         # 添加GET方式提交的参数70         if request.query_string:71             request_log = request_log + ' params(get):' + urllib.parse.unquote(str(request.query_string))72         # 添加POST方式提交的参数73         if request.method == 'POST':74             request_log = request_log + ' params(post):' + urllib.parse.unquote(str(request.params.__dict__))75         # 存储到日志文件中76         log_helper.info(request_log)77     except:78         pass79 80     # 处理ajax提交的put、delete等请求转换为对应的请求路由(由于AJAX不支持RESTful风格提交,所以需要在这里处理一下,对提交方式进行转换)81     if request.method == 'POST' and request.POST.get('_method'):82         request.environ['REQUEST_METHOD'] = request.POST.get('_method', '')83 84     # 过滤不用进行登录权限判断的路由(登录与退出登录不用检查是否已经登录)85     url_list = ["/api/login/", "/api/logout/"]86     if path_info in url_list:87         pass88     else:89         # 已经登录成功的用户session肯定有值,没有值的就是未登录90         session = web_helper.get_session()91         # 获取用户id92         manager_id = session.get('id', 0)93         login_name = session.get('login_name', 0)94         # 判断用户是否登录95         if not manager_id or not login_name:96             web_helper.return_raise(web_helper.return_msg(-404, "您的登录已失效,请重新登录"))97 98 99
100 # 函数主入口
101 if __name__ == '__main__':
102     app_argv = SessionMiddleware(default_app(), session_opts)
103     run(app=app_argv, host='0.0.0.0', port=9090, debug=True, reloader=True)
104 else:
105     # 使用uwsgi方式处理python访问时,必须要添加这一句代码,不然无法访问
106     application = SessionMiddleware(default_app(), session_opts)

  main.py文件里有详细的注释说明,所以不进行细说,在这里讲一讲文件大体的思路。

  因为我们编写的接口文件都放在api文件夹中,当web服务启动后需要将api里的接口文件自动装载进来,让我们可以通过url访问里面的接口,所以需要在main.py这个入口函数中,对api文件夹里的接口文件进行导入,前面讲解到我们api文件夹里有一个__init__.py文件,它会自动帮我们导入当前文件夹里的所有文件,所以我们只需要在main.py中添加import api这一行代码就可以了。

  另外,我们需要告诉python服务当前程序所在的路径,所以需要将当前文件所在的绝对路径添加到python环境变量中(第21到23行)

  我们要记录异常信息到日志,要记录客户端访问的url与提交的请求参数,方便出错时帮助我们进行排查错误,所以要初始化日志文件格式与存储路径(第30到39行)

  bottle框架有两个好用的勾子处理函数(具体流程如下图),客户端访问接口时,首先会从bottle web服务绑定的入口进入,然后调用before_request这个勾子函数(第50到97行),执行完里面的代码后再进入对应的接口函数里,当接口函数运行完毕后,又会调用after_request这个勾子函数(我们使用了nginx处理前端访问服务不存在跨域问题,所以main.py就没有添加这个勾子函数),运行完里面的代码后才返回最终结果给客户端。所以我们有很多事情可以放在这两个勾子函数中进行处理。before_request中我们可以运行初始化操作、记录客户端访问的url与提交的请求参数操作、判断用户是否已经登录等操作(如果没有这个勾子函数,我们要判断用户是否登录,就必须在每个接口文件中处理,这样一方面代码会很冗余,出现大量重复的没有必要的代码,另一方面也很容易出错或遗漏掉,造成后端权限访问漏洞。而after_request这个函数通过是用来处理输出HTTP头信息等内容,比如跨域处理等。

  

  第55到78行,会将客户端访问的url与各种方式提交的请求参数记录到日志。对于一些不想记录到日志的访问,可以添加到第57行。(如下图)

  

  第90到96行,对登录用户访问进行处理,如果未登录的,则会返回-404状态,客户端的ajax接收到这个状态后,自行处理跳转到登录页面。

  验证码接口

  我们在api文件夹中创建verify.py文件

#!/usr/bin/python
#coding: utf-8from io import BytesIO
from bottle import get, response
from common import verify_helper, log_helper, web_helper@get('/api/verify/')
def get_verify():"""生成验证码图片"""try:# 获取生成验证码图片与验证码code_img, verify_code = verify_helper.create_verify_code()# 将字符串转化成大写保存到session中s = web_helper.get_session()s['verify_code'] = verify_code.upper()s.save()# 输出图片流buffer = BytesIO()code_img.save(buffer, "jpeg")code_img.close()response.set_header('Content-Type', 'image/jpg')return buffer.getvalue()except Exception as e:log_helper.error(str(e.args))

  code_img, verify_code = verify_helper.create_verify_code() :运行verify_helper.create_verify_code() ,会返回图片流和验证码,python语言执行函数后,可以直接返回字符串、数值、元组、字典、列表等各种类型的值,返回元组类型值时,就可以使用这样的方式进行接收。

  log_helper.error(str(e.args))  这是我们前面工具函数包时所讲到的错误记录函数,当生成验证码出现异常时,它会将异常信息记录到日志文件中,并将异常发送到我们指定的邮箱。

  添加完这个文件后,我们就可以运行一下main.py,然后在浏览器中输入http://127.0.0.1:9090/api/verify/或http://127.0.0.1:81/api/verify/,就可以看到生成的验证码了(如果使用81端口无法访问)

  

  登录接口

  我们在api文件夹中创建login.py文件

 1 #!/usr/bin/evn python2 # coding=utf-83 4 from bottle import put5 from common import web_helper, encrypt_helper, db_helper6 7 8 @put('/api/login/')9 def post_login():
10     """用户登陆验证"""
11     ##############################################################
12     # 获取并验证客户端提交的参数
13     ##############################################################
14     username = web_helper.get_form('username', '帐号')
15     password = web_helper.get_form('password', '密码')
16     verify = web_helper.get_form('verify', '验证码')
17     ip = web_helper.get_ip()
18
19     ##############################################################
20     # 从session中读取验证码信息
21     ##############################################################
22     s = web_helper.get_session()
23     verify_code = s.get('verify_code')
24     # 删除session中的验证码(验证码每提交一次就失效)
25     if 'verify_code' in s:
26         del s['verify_code']
27         s.save()
28     # 判断用户提交的验证码和存储在session中的验证码是否相同
29     if verify.upper() != verify_code:
30         return web_helper.return_msg(-1, '验证码错误')
31
32     ##############################################################
33     ### 获取登录用户记录,并进行登录验证 ###
34     ##############################################################
35     sql = """select * from manager where login_name='%s'""" % (username,)
36     # 从数据库中读取用户信息
37     manager_result = db_helper.read(sql)
38     # 判断用户记录是否存在
39     if not manager_result:
40         return web_helper.return_msg(-1, '账户不存在')
41
42     ##############################################################
43     ### 验证用户登录密码与状态 ###
44     ##############################################################
45     # 对客户端提交上来的验证进行md5加密将转为大写(为了密码的保密性,这里进行双重md5加密,加密时从第一次加密后的密串中提取一段字符串出来进行再次加密,提取的串大家可以自由设定)
46     # pwd = encrypt_helper.md5(encrypt_helper.md5(password)[1:30]).upper()
47     # 对客户端提交上来的验证进行md5加密将转为大写(只加密一次)
48     pwd = encrypt_helper.md5(password).upper()
49     # 检查登录密码输入是否正确
50     if pwd != manager_result[0].get('login_password', ''):
51         return web_helper.return_msg(-1, '密码错误')
52     # 检查该账号虽否禁用了
53     if manager_result[0].get('is_enable', 0) == 0:
54         return web_helper.return_msg(-1, '账号已被禁用')
55
56     ##############################################################
57     ### 把用户信息保存到session中 ###
58     ##############################################################
59     manager_id = manager_result[0].get('id', 0)
60     s['id'] = manager_id
61     s['login_name'] = username
62     s.save()
63
64     ##############################################################
65     ### 更新用户信息到数据库 ###
66     ##############################################################
67     # 更新当前管理员最后登录时间、Ip与登录次数(字段说明,请看数据字典)
68     sql = """update manager set last_login_time=%s, last_login_ip=%s, login_count=login_count+1 where id=%s"""
69     # 组合更新值
70     vars = ('now()', ip, manager_id,)
71     # 写入数据库
72     db_helper.write(sql, vars)
73
74     return web_helper.return_msg(0, '登录成功')

  在编写登录接口前,我们首先要了解登录接口处理的流程是怎么样的

  

  login.py后台登录处理接口代码可以看到,路由我们使用的是@put('/api/login/'),RESTful风格中,post是用于新增记录,put是用于修改或改变服务器数据,登录我理解它肯定不是新增,它是改变用户登录的状态,所以这里使用put方式接收

  登录接口的代码有详细的注释,还有上面的流程图,所以就不再深入解说,大家自己看代码,如有不明白的,文章后面留言。

  前端登录html页面(login.html)

  1 <!DOCTYPE HTML>2 <html>3 <head>4     <meta charset="utf-8">5     <meta name="renderer" content="webkit|ie-comp|ie-stand">6     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">7     <meta name="viewport"8           content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>9     <meta http-equiv="Cache-Control" content="no-siteapp"/>10     <!--[if lt IE 9]>11     <script type="text/javascript" src="lib/html5shiv.js"></script>12     <script type="text/javascript" src="lib/respond.min.js"></script>13     <![endif]-->14     <link href="static/h-ui/css/H-ui.min.css" rel="stylesheet" type="text/css"/>15     <link href="static/h-ui.admin/css/H-ui.login.css" rel="stylesheet" type="text/css"/>16     <link href="static/h-ui.admin/css/style.css" rel="stylesheet" type="text/css"/>17     <link href="lib/Hui-iconfont/1.0.8/iconfont.css" rel="stylesheet" type="text/css"/>18     <!--[if IE 6]>19     <script type="text/javascript" src="lib/DD_belatedPNG_0.0.8a-min.js"></script>20     <script>DD_belatedPNG.fix('*');</script>21     <![endif]-->22     <title>后台登录 - H-ui.admin v3.1</title>23     <meta name="keywords" content="H-ui.admin v3.1,H-ui网站后台模版,后台模版下载,后台管理系统模版,HTML后台模版下载">24     <meta name="description" content="H-ui.admin v3.1,是一款由国人开发的轻量级扁平化网站后台模板,完全免费开源的网站后台管理系统模版,适合中小型CMS后台系统。">25 </head>26 <body>27 <input type="hidden" id="TenantId" name="TenantId" value=""/>28 <div class="header"></div>29 <div class="loginWraper">30     <div id="loginform" class="loginBox">31         <form class="form form-horizontal">32             <div class="row cl">33                 <label class="form-label col-xs-3"><i class="Hui-iconfont"></i></label>34                 <div class="formControls col-xs-8">35                     <input id="username" name="username" type="text" placeholder="账号" class="input-text size-L">36                 </div>37             </div>38             <div class="row cl">39                 <label class="form-label col-xs-3"><i class="Hui-iconfont"></i></label>40                 <div class="formControls col-xs-8">41                     <input id="password" name="password" type="password" placeholder="密码" class="input-text size-L">42                 </div>43             </div>44             <div class="row cl">45                 <div class="formControls col-xs-8 col-xs-offset-3">46                     <input id="verify" name="verify" class="input-text size-L" type="text" value=""47                            style="width:150px;">48                     <img style="width: 100px;height: 40px;padding: 0px;vertical-align:middle" id="verifycode"49                          src="/api/verify/" οnclick="get_verify()"> <a href="javascript:;" οnclick="get_verify()">看不清,换一张</a></div>50             </div>51             <div class="row cl">52                 <div>53                     <h5 class="formControls col-xs-8 col-xs-offset-3"><span id="msg" style="color:#F00"></span></h5>54                 </div>55             </div>56             <div class="row cl">57                 <div class="col-xs-8 col-xs-offset-3">58                     <input type="button" class="btn btn-success size-L" οnclick="submit1()"59                            value="&nbsp;登&nbsp;&nbsp;&nbsp;&nbsp;录&nbsp;">60                 </div>61             </div>62         </form>63     </div>64 </div>65 <div class="footer">Copyright 你的公司名称 by H-ui.admin v3.1</div>66 <script type="text/javascript" src="lib/jquery/1.9.1/jquery.min.js"></script>67 <script type="text/javascript" src="static/h-ui/js/H-ui.min.js"></script>68 <script>69     function submit1() {70         if ($("#username").val().trim().length == '') {71             $("#msg").html('').append('请输入用户名');72         }73         else if ($("#password").val().trim().length == '') {74             $("#msg").html('').append('请输入登录密码');75         }76         else if ($("#verify").val().trim().length != 4) {77             $("#msg").html('').append('请输入4位图形验证码');78         } else {79             username = $("#username").val();80             password = $("#password").val();81             verify = $("#verify").val();82             $.ajax({83                 type: 'POST',84                 url: "/api/login/",85                 data: {'_method': 'put', 'username': username, 'password': password, 'verify': verify},86                 dataType: 'json',87                 success: function (data) {88                     if(data && data.state>-1){89                         $(location).prop('href', 'main.html');90                     }91                     else{92                         $("#msg").html('').append(data.msg);93                         get_verify();94                     }95                 },96                 error: function(data){97                     if (data){98                         alert(data.msg);99                     }
100                     get_verify();
101                 }
102             });
103         }
104     }
105
106     function get_verify() {
107         $("#verifycode").attr("src", "/api/verify/?" + 100 * Math.random());
108     }
109
110 </script>
111 </body>
112 </html>

  对前面下载的login.html页面进行了微调,添加了请求的AJAX代码。

  由于火狐和谷歌运行AJAX不支持PUT、DELETE等提交方式,所以AJAX提交时type类型还是POST方式,在提交参数项里面,需要增加 _method 这个参数,值为put。(由于本系列使用的是RESTful风格,所以虽然有点麻烦,但不影响我们的使用)

  html和js我也不进行详细说明,大家自己看代码吧,如果大家都要求需要对js写注释的,我到时再添加注释进去。

  相关页面功能都完成了,接下来就是进行运行调试

  在浏览器中输入:http://127.0.0.1:81/login.html 然后输入账号:admin,密码:123456,还有验证码

  

  点击登录,能正常跳转到http://127.0.0.1:81/main.html 页面,就表示登录接口能正常使用了。

  

  大家想要熟悉登录接口代码的运行,最好使用debug运行跟踪一下,看看每一行代码是怎么运行的,就清楚了。当然如果想要加深理解,最佳方式是照着代码手打一次,每完成几行就debug运行一下,看看执行效果。

转载于:https://www.cnblogs.com/klb561/p/8688218.html

免密登录-python相关推荐

  1. python pexpect telnet_使用python的pexpect模块,实现远程免密登录的示例

    说明 当我们需要用脚本实现,远程登录或者远程操作的时候,都要去解决如何自动输入密码的问题,一般来说有3种实现方式: 1).配置公钥私钥 2).使用shell下的命令,expect 3).使用pytho ...

  2. cookie 免密登录_python

    我们都知道 HTTP 是无状态的,用户每次打开 web 页面时,服务器都打开新的会话,而且服务器也不会自动维护客户的上下文信息,那么服务器是怎么识别用户的呢? 这就是本文今天要讲解的内容.当服务端需要 ...

  3. flask框架如何实现修改密码和免密登录功能

    flask是python web开发的常用框架之一.本文将讲述flask如何实现修改密码和免密登录功能 修改密码功能 数据库部分: #重置密码 def reset_pass(phone,passwor ...

  4. selenium操作cookies实现免密登录,自动发微博

    一直想用selenium实现个小功能,比如发微博之类的,但是有的网站在登录会有验证码,没想到太好的方法解决,于是想到利用cookies来登录网站 第一步:获取一个可用的cookies,获取的cooki ...

  5. 关于设置不同linux主机之间ssh免密登录简易方法

    2019独角兽企业重金招聘Python工程师标准>>> 在linux日常中,经常会有ssh链接其他主机服务器的action,也学习过大家日常用配置ssh免密登录的方法. 小编今天在这 ...

  6. ssh 免密登录并用脚本群起服务

    2019独角兽企业重金招聘Python工程师标准>>> 让普通用户可以sudo,并且不需要输入密码 [root@hadoop13 bin]# visudo ## Allow root ...

  7. 深度解读SSH免密登录

    转载自公众号:未闻Code 我们都知道SSH是LINUX下很常用的命令,用来远程登陆其他的LINUX系统.如果只有一台,那也只是一个密码 ,也倒还好.但如果是一个集群,每次都输入密码登录,难免会拉低效 ...

  8. Linux基础, 基础命令, 基于公钥的免密登录

    安装Linux虚拟机时, 点选web web server, 再勾选development tools, 解决很多命令还需要用yum安装的问题 reboot命令用于重启机器 poweroff用于关闭系 ...

  9. pythoncookie自动登录_Python使用cookie 免密登录了解一下

    我们都知道 HTTP 是无状态的,用户每次打开 web 页面时,服务器都打开新的会话,而且服务器也不会自动维护客户的上下文信息,那么服务器是怎么识别用户的呢? 这就是本文今天要讲解的内容.当服务端需要 ...

最新文章

  1. 最新zendframework1.11使用
  2. 学python好不好-26岁了,自学Python怎么样?
  3. Java线程详解(5)-线程的同步与锁
  4. 跨页数据传递的两种方式
  5. Gentle.Net学习笔记四:修改代码,使用Oracle数据库
  6. UI设计灵感|注册登录界面设计灵感
  7. 贵安新区构建大数据+物联网+智能制造产业链
  8. 常用html标签 —— 链接的颜色
  9. access游戏库不显示 ea_全球游戏公司营收一览:腾讯连续第六年霸榜
  10. 我在百度运维的成长经历 之六
  11. 【python】Tkinter窗口可视化二
  12. canvas画布会黑屏吗_你真的会绷油画布吗?
  13. 访问kubernetes dashboard UI报错
  14. 好用的滚动式截图工具picpick
  15. 21届校招中获得12家公司offer的一些经验(包括6家银行信息科技岗offer)
  16. python武器代码_武器代码总结大全 BO开启秘籍的方法
  17. c语言程序设计 葛日波,C语言程序设计课程教学改革的探索
  18. multiwii 2.4配置中文注释
  19. MySQL 数据库基础
  20. wifi分析仪怎么看哪个信道好_(一百零四)探讨WiFi分析仪如何获取信道的?

热门文章

  1. 前端技术周刊 2019-02-11 Serverless
  2. java基础-多线程应用案例展示
  3. Vue按需加载提升用户体验
  4. 《Linux KVM虚拟化架构实战指南》——第1章 KVM虚拟化概述 1.1XEN虚拟化介绍
  5. 121 项目 024 笔记向 内省机制
  6. win7下的python2.7和pip的环境安装
  7. Eclipse快捷键大全(同样适用基于Eclipse开发的IDE)
  8. linux任务计划学习
  9. javascript实现的自适应宽度的瀑布流
  10. RedHat Linux 5企业版开启VNCSERVER远程桌面功能[转]