【Python】基于基于Pyqt和Bmob数据库的在线登录模块
## 0x0 起因因为不会给动图打码,就只用静态截图了。
[!(https://z3.ax1x.com/2021/08/26/hu1HMQ.png)](https://imgtu.com/i/hu1HMQ)
这个想法其实是因为之后要把之前写的易班工具拿给新来的干事用,考虑到部分人没有基础,让他们在源码里面改参数不太现实(可能教他们配置环境都会很头疼)。于是就产生了给工具写一个GUI的想法,在看了Tkinter和PyQt之后感觉似乎Qt的资料要多一点点,于是选择了Qt。
稍微扯远了点,这个小模块就是一个小练手,本质上这个小模块的登录等一系列的验证都是通过**requests库**和**Bmob官方库**实现的;我想的是,先至少摸到Qt门槛,再去把工具接进去,不然不知道要遇到多少奇奇怪怪的bug。
接着就开始着手去做这个小程序了
目前已实现功能:
1. 通过Bmob验证用户身份
2. 单用户登录校验码,一次性校验码
3. 登录记录
4. 通过Server酱推送登录通知
计划功能:
1. 添加校验码
2. 本地记住BmobKey
------
## 0x1 UI部分
昨天(8/25)下午开始画UI,有一说一,QtDesigner是个好东西,拖几下基本框架就有了。然后稍微改一下细节,就差不多了。左边这个是QtDesigner直出的UI,稍微缺点内味。利用万能的互联网发现Qt可以支持类似CSS的样式文件——QSS,二者语法是完全一样的。然后在GayHub上头找到了一个现成的Qss模板,稍微修改了一下,就有了右侧的这样。圆角yyds!!!
~~PS:本来还想把整个窗体都做成圆角的,但是好像挺复杂的样子,就放弃了。~~
[!(https://z3.ax1x.com/2021/08/25/heGEFK.png)](https://imgtu.com/i/heGEFK)
我觉得我审美应该是挺在线的,我把截图拿给女朋友和好兄弟们看,评价都是
> 有点丑,但是又不知道哪丑,像是世纪初的软件
多少想哭。
------
撇开美观与否,简单聊一聊我的思路。
通过小学数学学到的数数方法,可以知道整个窗口上有六个输入栏,三个按钮和一个CheckBox(暂时`加码`和`记住Key`暂时是没用的,还没写功能)。
整个小程序的逻辑是,先输入Bmob的Key,选择性输入Server酱的SendKey;先简单判断Bmob的那两个输入栏是否为空,为空则显示提示文字,如果有输入则尝试连接Bmob(暂时没做更详细的验证),并且激活下面的登录按钮,因为按照当时写的登录函数的逻辑,如果都输入为空的话,似乎会出现奇怪的Bug直接卡死,大概就是下面这个样子。~~主要是懒得改~~
[!(https://z3.ax1x.com/2021/08/26/hn48l8.gif)](https://imgtu.com/i/hn48l8)
接着再输入账号、密码和校验码(选填),再连接Bmob验证,并根据返回的结果显示对应的文字提示。其中是否需要校验码可以在Bomb后台对表单进行修改来实现控制。
以上是已实现的功能,下面是计划中的功能。
第一个就是记住Key的功能
每一次打开都要输入显得挺麻烦的,可以考虑在根目录生成cfg文件,记录Key,在程序加载时先判断根目录是否有cfg文件,如果有就看看是否保存有key并且修改CheckBox状态,如果没有就新生成一个。
[!(https://z3.ax1x.com/2021/08/25/heab1f.png)](https://imgtu.com/i/heab1f)
第二个就是向后台增加校验码
函数其实已经写好了,但是还没写到主程序里。这个各位就自己看看`ActCode.py`就可以了,很简单的一个功能。
其他就没啥好说的了吧,QtDesigner那个东西没啥好说的,半小时应该就能掌握基本操作了。
------
## 0x2 登录函数实现
这个函数其实挺早就写好了,但是当时是控制台脚本,就花了点时间去把他给按照我对Qt粗浅的理解修改了一下。下面简单的说一下思路吧。
首先要说明的是,整个业务逻辑都是依赖于Bmob的官方库实现的,Bmob官方也给了一些简单的例子(虽然都是18年的了),先行阅读Bmob的官方文档有利于理解后面的内容。因为没有写创建用户的脚本,所以创建用户等操作都需要自己先行手动创建,具体可以参考下方截图抄作业。
(放图)
链接:(http://doc.bmob.cn/data/python/index.html)
有的老哥会问,为什么不用MySQL或者MongoDB这些数据库呢?
我学的不是计算机专业,纯属自己瞎鼓捣着玩,也就脚本小子的程度,我对数据库的认识就只有`rm -rf /*`这样,虽然有自己的服务器,但是平时玩WordPress这些基本上都是能不动就不会去动数据库。所以就没有去系统学习过数据库相关的内容。Bmob这个网站我高三就用过了,感觉也海星,挂一点小玩具的数据在上头跑路了也不影响。
最重要的就是他挺简单的,好上手,基本上当时从看他的Demo到自己写出来这个登录程序也就花了小半天,可以说是有Python基础基本就能懂,也不需要额外配置什么,直接注册个账号创建应用有Key就可以开搞了;而且,他免费(这才是重中之重,盒盒盒)。
~~Bmob快给我打钱!!!~~
### 1. 登录&验证
首先,Bmob官方给了一个登录函数
| userLogin(username, password) | HttpResponse | 用户通过账号、密码登陆 |
| ----------------------------- | ------------ | ---------------------- |
```python
def Login(user, passwd, APP_id, API_key):
b = Bmob(APP_id, API_key) #实例化
account = b.userLogin(user, passwd)
return account.status #返回登录结果
```
其中status为Bmob模块内置的响应类型
| status | str| 状态信息 |
| ------ | ---- | -------- |
这里如果密码账号正确就会返回字符串“OK”,那么很简单的一个if判断就可以判断登录结果了。
```python
if Login(user, passwd, APP_id, API_key) == "OK":
print("登录成功!")
else:
print("用户名或密码错误!")
```
实现登录功能后,我们来解决校验码的问题。首先肯定是检查当前用户是否需要校验码,然后再检查用户提供的校验码是否存在。这个就没有现成的方法来调用了,得自己写,但是也不难。
通过官方文档我们可以找到`find`函数,似乎符合我们的要求,并且官方也给了具体的例子
```python
b = Bmob("appid", "restkey")
b.find(
table, # 设置查询表单
where = None, # 设置查询条件, dict或BmobQuerier
limit = None, # 设置最大返回行数,int
skip = None, # 设置跳过的个数,int
order = None, # 排序规则,str
include = None, # 需要返回详细信息的Pointer属性,str
keys = None, # 需要返回的属性,str
count = None, # 统计接口: 返回数量,int
groupby = None, # 统计接口: 根据某列分组,str
groupcount = None, # 统计接口: 分组后组内统计数量,bool
min = None, # 统计接口: 获取最小值,str
max = None, # 统计接口: 获取最大值,str
sum = None, # 统计接口: 计算总数,str
average = None, # 统计接口: 计算平均数,str
having = None, # 统计接口: 分组中的过滤条件,str
objectId = None # 查询单条数据,str
)
```
可以说是就差把程序写好丢你脸上了。`table`是要查询的表单,待会儿我们去建一个存放校验码的表。然后就是`where`,可以看到他有两种方法,一个是dict、一个是BmobQuerier。先不考虑dict,看看Bmob自己给的这个方法,通过阅读文档可以找到这么一段说明
### BmobQuerier
**类方法**: **返回类型均为 `BmobQuerier`** (以链式调用)
| 方法体 | 描述 |
| :----------------------------------------------------------- | :------------------------------- |
| addWhereExists(key) | 某字段有值 |
| addWhereNotExists(key) | 某字段无值 |
| addWhereEqualTo(key, value) | 某字段等于 |
| addWhereNotEqualTo(key, value) | 某字段不等于 |
| addWhereGreaterThan(key, value) | 某字段大于 |
| addWhereGreaterThanOrEqualTo(key, value) | 某字段大于等于 |
| addWhereLessThan(key, value) | 某字段小于 |
| addWhereLessThanOrEqualTo(key, value) | 某字段小于等于 |
| addWhereRelatedTo(table,toObjId,toKey) | 在某表作为Relation关联起来的数据 |
| addWhereNear(key,bmobGeoPoint,maxMiles,maxKM,maxRadians) | 地理位置在一定范围内 |
| addWhereWithinGeoBox(key,southwest,northeast) | 地理位置在矩形范围内 |
| addWhereContainedIn(key,objs) | 值在列表内 |
| addWhereNotContainedIn(key,objs) | 值不在列表内 |
| addWhereContainsAll(key,objs) | 列表包含全部项 |
| addWhereStrContains(key,regex) | String类型模糊查询 |
| addWhereMatchesSelect(key,innerQuery,innerKey,innerTable,isMatch) | 某项符合子查询 |
| addWhereInQuery(key,value,className,isIn) | 某项包含在子查询 |
那么,我们如果要检查一个校验码是否存在,那么就是去遍历表,挨个比对是否有这么一个校验码;不难发现上面有一个方法可以实现这个功能——`addWhereEqualTo(key, value)`,需要注意的是这里是用value的值去和key这个字段里的所有值进行比较,所有就不用再去写循环了,很棒
```python
b = Bmob(APP_id, API_key)
b.find('ActCode', where=BmobQuerier().addWhereEqualTo("actcode", jycode)).queryResults['objectId']
```
其中queryResults为Bmob模块的内置响应类型
| queryResults | dict | 返回的bmob查询数据 |
| ------------ | ---- | ------------------ |
这里我们用`jycode`在表`ActCode`中的`actcode`字段中进行对比,如果`jycode`在`actcode`字段中存在,那么将会返回该校验码对应的`objectid`;如果不存在,则`b.find(...)`将不会存在`queryResults`,发生`IndexError`错误,那么可以使用`try...except...`的方法来写这个验证,即
```python
def actcode(code, APP_id, API_key):
b = Bmob(APP_id, API_key)
try:
object_id = b.find('ActCode', where=BmobQuerier().addWhereEqualTo("actcode", code)).queryResults['objectId']
b.remove('ActCode', object_id)
return code
except IndexError:
return 0
```
这里的`remove`函数用来删除上面使用的这个校验码,通过返回的objectid,在`ActCode`表中删除对应行
| remove(className, objectId) | 删除数据表中的一行 |
| --------------------------- | ------------------ |
以上,我们实现了登录和验证校验码的功能
### 2. 校验码控制
这里,我们将实现单用户校验码控制,即可设置哪些用户需要校验码登录,哪些用户不需要。
主要的思路和上面的验证码校验差不多,我们通过在`_User`表中,新建一个校验码控制字段`ctrlcode`,通过对`ctrlcode`字段的修改实现单个用户的校验码设置。直接上代码
```python
def Ctrl(User, APP_id, API_key):
b = Bmob(APP_id, API_key)
flag = b.find('_User', where=BmobQuerier().addWhereEqualTo("username", User)).queryResults['ctrlcode']
return flag
```
这里返回的是查询的结果,我们将`ctrlcode`字段设为`Number`或者`Bool`型都是可以的,将函数返回的结果代入到大的登录函数中,就可以在登录时决定是否调用校验码验证函数。
### 3. 登录记录
这里需要将登录用户和使用的校验码记录下来,因为Bmob自带时间记录,所以不再单独写函数上传时间。需要用到`insert`函数:
| insert(className, data) | 往数据表中添加一行 |
| ----------------------- | ------------------ |
传入用户名和使用的校验码即可,如果不使用校验码则将校验码设为用户名:
```python
def up_log(User, code, APP_id, API_key):
b = Bmob(APP_id, API_key)
b.insert('log', {
'username': user,
'usecode': code
})
```
| objectId | usecode | username | createdAt | updateAt |
| ---------- | --------------- | -------- | ------------------- | ------------------- |
| 82faea999d | tool-6t&ZFaq<Zz | toolman| 2021-08-25 22:23:04 | 2021-08-25 22:23:04 |
这样就向`log`表中上传了登录信息,并且如果用户使用过校验码也能记录校验码。
### 4. Server酱推送
通过server酱的官方文档,我们直接使用requests库来实现,这里不多赘述,直接看代码
```python
def wxpush(user, code, send_key):
sApi = 'https://sctapi.ftqq.com/' + send_key + '.send'
requests.post(sApi, {
'title': '登录提示',
'desp': '用户 ' + user + ' 登录成功!\n使用了激活码:' + code
})
```
最后将这些模块组装起来就可以了。
------
## 0x3 Qt踩坑部分
这一小节我认为是我整篇帖子里最有用的部分。我希望把我在写这个小程序时遇到的问题分享出来,大家自己上手的时候就可以避免这些情况。
这点明天再更新,今晚收拾东西,明儿回学校,四月份受伤韧带断了就一直休学在家里,太难受了。
页:
[1]