使用 pywebio 实现简易的工具箱网页(带登录态)

发布时间 2023-08-30 23:32:35作者: coreylin

使用 pywebio 实现简易的工具箱网页(带登录态)

背景说明

简单做一个网页放个人服务器,展示一些自己常用的工具脚本,而且支持直接在网页运行工具,这样方便自己随时随地需要触发一些任务。

由于是直接在个人服务器上运行脚本,需要有一定的权限控制,避免被其他人误操作。因此采用 pywebio 这样一个轻量级的工具,好处是不用去写一个单独的前端,而且大部份工具脚本都是 python 编写,调用方便。

效果

  • 登录页面

  • 应用列表(登录后)

  • 应用页面(app1)

import functools
import pywebio
from pywebio.input import *
from pywebio.output import *
from pywebio.session import *
from pywebio.platform.page import get_static_index_content
from tornado.web import create_signed_value, decode_signed_value

class LocalStorage():
    @staticmethod
    def set(key, value):
        run_js("localStorage.setItem(key, value)", key=key, value=value)

    @staticmethod
    def get(key):
        return eval_js("localStorage.getItem(key)", key=key)

    @staticmethod
    def remove(key):
        print(f"remove {key}")
        run_js("localStorage.removeItem(key)", key=key)

# 定义一个装饰,用于检查用户是否已登录
def login_required(func):
    # 使用 functools.wraps,保持函数名称不变
    @functools.wraps(func)
    def warpper(*args, **kwargs):
        token = LocalStorage().get('token')
        print(f"token = {token}")
        username = decode_signed_value(SECRET, 'token', token, max_age_days=7) 
        print(f"username = {username}")
        if not token or not username:  # no token or token validation failed
            return login()
        return func(*args, **kwargs)
    return warpper


def check_user(username, password):
    # 检查用户名密码是否正确
    return True

# 加盐
SECRET = "encryption salt value"


def login():
    """Persistence auth

    Use a to signed token mechanism to generate a token store in user's web browser
    """
    user = input_group('Login', [
        input("Username", name='username'),
        input("Password", type=PASSWORD, name='password'),
    ])
    username = user['username']
    if check_user(username, user['password']):
        signed = create_signed_value(SECRET, 'token', user['username']).decode("utf-8") 
        LocalStorage().set('token', signed)
        LocalStorage().set('username', user['username'])
        return index()
    else:
        toast('Wrong password!', color='error')
        return index()

@login_required
def app1():
    """ 应用1

    应用1的说明
    """
    username = LocalStorage().get("username")
    put_markdown(f"# Hello {username}\nThis is a message from app1")

@login_required
def app2():
    """ 应用2

    应用1的说明
    """
    username = LocalStorage().get("username")
    put_markdown(f"# Hello {username}\nThis is a message from app2")


@login_required
def logout():
    """ 退出

    退出当前登录状态
    """
    LocalStorage().remove('token')
    toast("Logout Success !!", color='success')
    clear()
    return index()

@login_required
def index():
    """ 首页
    """
    applications = {f.__name__: f for f in apps if f.__name__ not in ['index']}
    content = get_static_index_content(applications)
    put_html(content)

if __name__ == '__main__':
    apps = [index, app1, app2, logout]
    pywebio.start_server(apps, port=80)