使用 Python 编写桌面图形界面程序之后,我们一般是直接使用 Pyinstaller 之类的工具打包成二进制文件,然后提供下载供用户使用。
这样做很方便,用户直接下载打开就可以使用了。但是同时也带来了一个风险,也就是软件传播的风险(如果程序涉及到一定的权限私密性的话)。
如何避免这种情况呢,一般是在服务器新起一个服务器认证后端,为程序添加一个用户认证的过程,如果用户认证不通过,则禁止登录,这也是很多 IM 产品的逻辑。
我们通过一个 Django 后端服务 和 PyQt5 来简单实现一下。
桌面客户端的实现
首先,创建一个桌面主窗口和一个登录窗口:
代码语言:javascript复制class LoginWindow(QtWidgets.QMainWindow):
def __init__(self):
super(LoginWindow, self).__init__()
self.setWindowTitle("登录 - 公众号:州的先生")
self.setFixedWidth(500)
self.main_widget = QtWidgets.QWidget()
self.main_layout = QtWidgets.QFormLayout() # 表单布局层
self.main_widget.setLayout(self.main_layout)
self.username_input = QtWidgets.QLineEdit() # 用户名输入框
self.pwd_input = QtWidgets.QLineEdit() # 密码输入框
self.pwd_input.setEchoMode(QtWidgets.QLineEdit.Password) # 密码输入框设置文本显示*号
self.login_btn = QtWidgets.QPushButton("登录") # 登录按钮
self.login_btn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
self.main_layout.addRow(self.tr("&用户名:"), self.username_input)
self.main_layout.addRow(self.tr("&密码:"), self.pwd_input)
self.main_layout.addRow(self.login_btn)
self.setCentralWidget(self.main_widget)
运行它,我们可以得到一个简单的登录窗口,如下图所示:
下面,我们再创建一个主窗口,当登录成功之后,程序自动切换到这个主窗口上:
代码语言:javascript复制class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("主窗口 - 公众号:州的先生")
self.setFixedSize(500,300)
接着在 LoginWindow 类里面新增一个名为 login 的方法,作为「登录」按钮点击的处理槽函数:
代码语言:javascript复制 # 登陆验证
def login(self):
username = self.username_input.text()
pwd = self.pwd_input.text()
if username == '' or pwd == '':
error_box = QtWidgets.QMessageBox()
error_box.setWindowTitle("出错!")
error_box.setIcon(QtWidgets.QMessageBox.Warning)
error_box.setText("请输入用户名或密码")
error_box.exec_()
else:
self.main_window = MainWindow()
self.main_window.show()
self.close()
在这里,我们只是对用户名和密码进行了简单的非空验证,如果存在空输入,则弹出错误提示款;如果都有输入,则切换到主窗口。
我们再将「登录」按钮的点击信号绑定到这个方法上:
代码语言:javascript复制self.login_btn.clicked.connect(self.login) # 绑定登录按钮点击信号
现在运行,可以看到实际的效果:
这样,我们在桌面客户端程序上的功能已经完成了。
后端认证系统的实现
下面,我们实现一个后端用户系统,用来验证桌面客户端程序输入而来的用户名密码是否正确。
新建一个Django项目
因为 Django 自带了一个强大的用户认证系统,所以我们直接使用它来作为我们桌面客户端程序的后端认证系统。
创建一个 Django 项目和 APP 应用:
生成和执行数据库迁移:
创建一个超级用户,用来管理后台:
启动开发服务器,可以发现系统已经运行正常了,我们进入到 Django 自带的强大后台管理界面:
我们在用户里面可以看到之前创建的超级用户:
创建一个用户登录的视图函数
有了后端的用户认证系统,我们继续在 Django 项目里面创建一个视图函数,用于接收客户端程序传输过来的用户名密码并进行验证。
打开 /qt_login_backend/app_auth/views.py 文件,在里面输入如下代码:
代码语言:javascript复制@csrf_exempt
def auth(request):
if request.method == 'POST':
username = request.POST.get('username','')
password = request.POST.get('password','')
if username != '' and password != '':
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return JsonResponse({'status':True})
else:
return JsonResponse({'status':False,'data':'用户被禁用'})
else:
errormsg = '用户名或密码错误!'
return JsonResponse({'status':False,'data':errormsg})
else:
errormsg = '用户名或密码未输入!'
return JsonResponse({'status':False,'data':errormsg})
else:
return JsonResponse({'status':False,'data':'方法不允许'})
然后在 /qt_login_backend/qt_login_backend/urls.py 文件中添加路由映射:
代码语言:javascript复制from app_auth import views
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/',views.auth),
]
桌面程序代码添加登录请求
完成了后端认证系统的构建之后,我们在图形界面程序代码里面对登录的槽函数进行一下修改,使用户输入的用户名和免能够发送到后端认证系统上进行认证,代码如下:
代码语言:javascript复制 # 登陆验证
def login(self):
username = self.username_input.text()
pwd = self.pwd_input.text()
if username == '' or pwd == '':
error_box = QtWidgets.QMessageBox()
error_box.setWindowTitle("出错!")
error_box.setIcon(QtWidgets.QMessageBox.Warning)
error_box.setText("请输入用户名或密码")
error_box.exec_()
else:
auth_url = 'http://127.0.0.1:8000/auth/'
r = requests.post(auth_url,
data={'username': username, 'password': pwd},
timeout=10
)
if r.status_code == 200:
resp_data = r.json()
if resp_data['status']:
self.main_window = MainWindow()
self.main_window.show()
self.close()
else:
error_box = QtWidgets.QMessageBox()
error_box.setWindowTitle("出错!")
error_box.setIcon(QtWidgets.QMessageBox.Warning)
error_box.setText(resp_data['data'])
error_box.exec_()
else:
error_box = QtWidgets.QMessageBox()
error_box.setWindowTitle("出错!")
error_box.setIcon(QtWidgets.QMessageBox.Warning)
error_box.setText('登录出错')
error_box.exec_()
这样,我们就完成了改造。下面来测试一下:
后续
除了验证用户,也有一部分的桌面程序是需要绑定机器进行限制的,如何实现这种限制功能呢?