我的第⼀个pythonweb开发框架(14)——后台管理系统登录功能
接下来正式进⼊⽹站的功能开发。要完成后台管理系统登录功能,通过查看登录页⾯,我们可以了解到,我们需要编写验证码图⽚获取接⼝和登录处理接⼝,然后在登录页⾯的HTML上编写AJAX。
在进⾏接⼝开发之前,还有⼀个重要的事情要处理,那就是对站点进⾏初始化,如果不进⾏初始化,那么独⽴⽂件编写的接⼝将会不到,要将异常错误写⼊⽇志⽂件也会不到路径,下⾯先上代码。
打开main.py⽂件,改为下⾯代码(⼤家可以⽐较⼀下和之前代码有什么不同)
1#!/usr/bin/evn python
2# coding=utf-8
3
4import bottle
5import sys
6import os
7import logging
8import urllib.parse
9from bottle import default_app, get, run, request, hook
10from beaker.middleware import SessionMiddleware
11
12# 导⼊⼯具函数包
13from common import web_helper, log_helper
14# 导⼊api代码模块(初始化api⽂件夹⾥的各个访问路由,这⼀句不能删除,删除后将⽆法访问api⽂件夹⾥的各个接⼝)
15import api
16
17>>>>>>>>>
18# 初始化bottle框架相关参数
19>>>>>>>>>
20# 获取当前main.py⽂件所在服务器的绝对路径
21 program_path = os.path.split(alpath(__file__))[0]
22# 将路径添加到python环境变量中
23 sys.path.append(program_path)
24# 让提交数据最⼤改为2M(如果想上传更多的⽂件,可以在这⾥进⾏修改)
25 bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 2
26
27>>>>>>>>>
28# 初始化⽇志相关参数
29>>>>>>>>>
30# 如果⽇志⽬录log⽂件夹不存在,则创建⽇志⽬录
31if not ists('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 = {
pe': 'file',
kie_expires': 3600,
45'session.data_dir': '/tmp/sessions/simple',
46'session.auto': True
47 }
48
49
50 @hook('before_request')
51def validate():
52"""使⽤勾⼦处理接⼝访问事件"""
53
54# 获取当前访问的Url路径
55 path_info = ("PATH_INFO")
56# 过滤不⽤做任何操作的路由(即过滤不⽤进⾏判断是否登录和记录⽇志的url)
57if path_info in ['/favicon.ico', '/', '/api/verify/']:
58return
59### 记录客户端提交的参数 ###
60# 获取当前访问url路径与ip
61 request_log = 'url:' + path_info + ' ip:' + _ip()
62try:
63# 添加json⽅式提交的参数
64if request.json:
65 request_log = request_log + ' params(json):' + urllib.parse.unquote(str(request.json))
66except:
67pass
68try:
69# 添加GET⽅式提交的参数
70if request.query_string:
71 request_log = request_log + ' params(get):' + urllib.parse.unquote(str(request.query_string))
72# 添加POST⽅式提交的参数
hod == 'POST':
74 request_log = request_log + ' params(post):' + urllib.parse.unquote(str(request.params.__dict__))
75# 存储到⽇志⽂件中
76 log_helper.info(request_log)
77except:
78pass
79
80# 处理ajax提交的put、delete等请求转换为对应的请求路由(由于AJAX不⽀持RESTful风格提交,所以需要在这⾥处理⼀下,对提交⽅式进⾏转换)
hod == 'POST'and ('_method'):
82 viron['REQUEST_METHOD'] = ('_method', '')
83
84# 过滤不⽤进⾏登录权限判断的路由(登录与退出登录不⽤检查是否已经登录)
85 url_list = ["/api/login/", "/api/logout/"]
86if path_info in url_list:
87pass
88else:
89# 已经登录成功的⽤户session肯定有值,没有值的就是未登录
90 session = _session()
91# 获取⽤户id
92 manager_id = ('id', 0)
93 login_name = ('login_name', 0)
94# 判断⽤户是否登录
95if not manager_id or not login_name:
96 urn_raise(urn_msg(-404, "您的登录已失效,请重新登录"))
97
98
99
100# 函数主⼊⼝
101if__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)
104else:
105# 使⽤uwsgi⽅式处理python访问时,必须要添加这⼀句代码,不然⽆法访问
106 application = SessionMiddleware(default_app(), session_opts)
View Code
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-8
from 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 = ate_verify_code()
# 将字符串转化成⼤写保存到session中
s = _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')
value()
except Exception as e:
(str(e.args))
code_img, verify_code = ate_verify_code() :运⾏ate_verify_code() ,会返回图⽚流和验证码,python语⾔执⾏函数后,可以直接返回字符串、数值、元组、字典、列表等各种类型的值,返回元组类型值时,就可以使⽤这样的⽅式进⾏接收。(verify_helper需要导⼊PIL包,在python3中已更改为pillow包了,所以我们需要执⾏pip进⾏安装:pip install pillow)
(str(e.args)) 这是我们前⾯⼯具函数包时所讲到的错误记录函数,当⽣成验证码出现异常时,它会将异常信息记录到⽇志⽂件中,并将异常发送到我们指定的邮箱。
登录接⼝
我们在api⽂件夹中创建login.py⽂件
1#!/usr/bin/evn python
2# coding=utf-8
3
4from bottle import put
5from common import web_helper, encrypt_helper, db_helper
6
7
8 @put('/api/login/')
9def post_login():
10"""⽤户登陆验证"""
11>>>>>>>>>>>>##
12# 获取并验证客户端提交的参数
13>>>>>>>>>>>>##
14 username = _form('username', '帐号')
15 password = _form('password', '密码')
16 verify = _form('verify', '验证码')
17 ip = _ip()
18
19>>>>>>>>>>>>##
20# 从session中读取验证码信息
21>>>>>>>>>>>>##
22 s = _session()
23 verify_code = s.get('verify_code')
24# 删除session中的验证码(验证码每提交⼀次就失效)
25if'verify_code'in s:
26del s['verify_code']
27 s.save()
28# 判断⽤户提交的验证码和存储在session中的验证码是否相同
29if verify.upper() != verify_code:
30return urn_msg(-1, '验证码错误')
31
32>>>>>>>>>>>>##
33### 获取登录⽤户记录,并进⾏登录验证 ###
34>>>>>>>>>>>>##
35 sql = """select * from manager where login_name='%s'""" % (username,)
36# 从数据库中读取⽤户信息
37 manager_result = ad(sql)
38# 判断⽤户记录是否存在
39if not manager_result:
40return urn_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# 检查登录密码输⼊是否正确
50if pwd != manager_result[0].get('login_password', ''):
51return urn_msg(-1, '密码错误')
52# 检查该账号虽否禁⽤了
53if manager_result[0].get('is_enable', 0) == 0:
54return urn_msg(-1, '账号已被禁⽤')html怎么实现登录验证功能
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
74return urn_msg(0, '登录成功')
View Code
在编写登录接⼝前,我们⾸先要了解登录接⼝处理的流程是怎么样的
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 >
48 <img id="verifycode"
49 src="/api/verify/" onclick="get_verify()"> <a href="javascript:;" onclick="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" ></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" onclick="submit1()"
59 value=" ;登 ;录 ">
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() {
70if ($("#username").val().trim().length == '') {
71 $("#msg").html('').append('请输⼊⽤户名');
72 }
73else if ($("#password").val().trim().length == '') {
74 $("#msg").html('').append('请输⼊登录密码');
75 }
76else 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) {
88if(data && data.state>-1){
89 $(location).prop('href', 'main.html');
90 }
91else{
92 $("#msg").html('').append(data.msg);
93 get_verify();
94 }
95 },
96 error: function(data){
97if (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>
View Code
对前⾯下载的login.html页⾯进⾏了微调,添加了请求的AJAX代码。
由于⽕狐和⾕歌运⾏AJAX不⽀持PUT、DELETE等提交⽅式,所以AJAX提交时type类型还是POST⽅式,在提交参数项⾥⾯,需要增加 _method 这个参数,值为put。(由于本系列使⽤的是RESTful风格,所以虽然有点⿇烦,但不影响我们的使⽤)
html和js我也不进⾏详细说明,⼤家⾃⼰看代码吧,如果⼤家都要求需要对js写注释的,我到时再添加注释进去。
相关页⾯功能都完成了,接下来就是进⾏运⾏调试
⼤家想要熟悉登录接⼝代码的运⾏,最好使⽤debug运⾏跟踪⼀下,看看每⼀⾏代码是怎么运⾏的,就清楚了。当然如果想要加深理解,最佳⽅式是照着代码⼿打⼀次,每完成⼏⾏就debug运⾏⼀下,看看执⾏效果。
版权声明:本⽂原创发表于,作者为本⽂欢迎转载,但未经作者同意必须保留此段声明,且在⽂章页⾯明显位置给出原⽂连接,否则视为侵权。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
小程序云开发-登录功能(手机号验证码登录)
« 上一篇
实现用户的登录注册功能
下一篇 »
推荐文章
热门文章
-
一种任意人头与任意人体的3D结合方法
2025-01-07 -
正则匹配c语言中8进制
2025-01-07 -
fortran数据格式
2025-01-07 -
python中文本转数字用的公式
2025-01-07 -
gh 文本变数值
2025-01-07 -
js判断输入是否为正整数、浮点数等数字的函数代码
2025-01-07 -
qt浮点数正则表达式
2025-01-07 -
QT正则表达式限制输入值
2025-01-07 -
手机号码和电话号码的正则表达式
2025-01-07 -
str转浮点-概述说明以及解释
2025-01-07 -
英豪结尾的诗句
2025-01-07 -
Java正则表达式:符合以特定字符串开头,以特定字符串结尾的所有结果
2025-01-07 -
machinebuilder使用手册
2025-01-07 -
ASP.NET网站建设基本常用代码
2025-01-07 -
LCD显示实时时钟
2025-01-07 -
经纬度正则表达式解析
2025-01-07 -
前端科学计数法转数字
2025-01-07 -
python正则表达式re之compile函数解析
2025-01-07 -
pythonunittest之断言及示例
2025-01-07 -
[lua]lua中匹配字符串小数
2025-01-07
最新文章
-
nginx map用法 正则
2025-01-07 -
Prometheus监控学习笔记之初识PromQL
2025-01-07 -
关于PHP中的webshell
2025-01-07 -
python中re.findall函数实例用法
2025-01-07 -
nginx url表达式
2025-01-07 -
nginx 正则匹配参数
2025-01-07
发表评论