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