当前位置: 首页 > article >正文

基于Flask的通用登录注册模块,并代理跳转到目标网址

实现了用户密码的加密,代理跳转到目标网址,不会暴露目标路径,未登录的情况下访问proxy则自动跳转到登录页,使用时需要修改配置项config,登录注册页面背景快速修改,可以实现登录注册模块的快速复用。

1.app.py

from flask import Flask, render_template, request, redirect, url_for, session, Response
import sqlite3
import os
import bcrypt
import requests

app = Flask(__name__)
app.secret_key = os.urandom(24)


# 数据库连接
def get_db():
    conn = sqlite3.connect('users.db')
    return conn


# 创建用户表
def create_user_table():
    conn = get_db()
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS users
                 (id INTEGER PRIMARY KEY AUTOINCREMENT,
                 username TEXT NOT NULL UNIQUE,
                 password TEXT NOT NULL)''')
    conn.commit()
    conn.close()


create_user_table()

# 配置项
config = {
    "after_login_url": "http://xxxx",  # 修改为目标网址
    "after_register_url": "/login",
    "login_background_image": "static/login_background.jpg",
    "register_background_image": "static/register_background.jpg"
}


# 检查用户是否登录的装饰器
def login_required(func):
    def wrapper(*args, **kwargs):
        if 'username' not in session:
            return redirect(url_for('login'))
        return func(*args, **kwargs)

    wrapper.__name__ = func.__name__
    return wrapper


# 注册页面
@app.route('/register', methods=['GET', 'POST'])
def register():
    error = None
    success = None
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password').encode('utf-8')
        hashed = bcrypt.hashpw(password, bcrypt.gensalt())

        conn = get_db()
        c = conn.cursor()
        try:
            c.execute("INSERT INTO users (username, password) VALUES (?,?)", (username, hashed))
            conn.commit()
            success = "注册成功!请登录。"
        except sqlite3.IntegrityError as e:
            print(f"IntegrityError: {e}")
            error = "用户名已存在,请选择其他用户名。"
        finally:
            conn.close()
    return render_template('register.html', error=error, success=success,
                           background_image=config["register_background_image"])


# 登录页面
@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password').encode('utf-8')
        remember_me = request.form.get('remember_me')

        conn = get_db()
        c = conn.cursor()
        c.execute("SELECT password FROM users WHERE username =?", (username,))
        user = c.fetchone()
        conn.close()

        if user:
            stored_password = user[0]
            if bcrypt.checkpw(password, stored_password):
                session['username'] = username
                if remember_me:
                    session.permanent = True
                return redirect(url_for('proxy'))
        error = "用户名或密码错误。"

    return render_template('login.html', error=error, background_image=config["login_background_image"])


# 注销
@app.route('/logout')
def logout():
    session.pop('username', None)
    return redirect(url_for('login'))


# 代理请求
@app.route('/proxy')
@login_required
def proxy():
    target_url = config["after_login_url"]
    try:
        resp = requests.get(target_url, headers=dict(request.headers))
        excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
        headers = [(name, value) for (name, value) in resp.raw.headers.items()
                   if name.lower() not in excluded_headers]
        return Response(resp.content, resp.status_code, headers)
    except requests.RequestException as e:
        return f"请求出错: {str(e)}", 500


# 将根目录设置为跳转到代理路由
@app.route('/')
@login_required
def index():
    return redirect(url_for('proxy'))


if __name__ == '__main__':
    app.run(debug=True)

2.login.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
    <!-- 使用 url_for 生成 CSS 文件的绝对路径 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background-image: url('{{ background_image }}');
            background-size: cover;
            background-repeat: no-repeat;
            background-position: center center;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }

       .card {
            border: none;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            background-color: rgba(255, 255, 255, 0.9);
        }

       .card:hover {
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
        }

       .card-header {
            background-color: #0d6efd;
            color: white;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
        }

       .alert {
            margin-top: 15px;
        }
    </style>
</head>

<body>
    <div class="container d-flex justify-content-center align-items-center vh-100">
        <div class="card w-50">
            <div class="card-header text-center">
                <h2>登录</h2>
            </div>
            <div class="card-body">
                {% if error %}
                <div class="alert alert-danger" role="alert">
                    {{ error }}
                </div>
                {% endif %}
                <form method="post">
                    <div class="mb-3">
                        <label for="username" class="form-label">用户名:</label>
                        <input type="text" id="username" name="username" class="form-control" required>
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">密码:</label>
                        <input type="password" id="password" name="password" class="form-control" required>
                    </div>
                    <div class="form-check mb-3">
                        <input class="form-check-input" type="checkbox" value="1" id="remember_me" name="remember_me">
                        <label class="form-check-label" for="remember_me">
                            记住密码
                        </label>
                    </div>
                    <button type="submit" class="btn btn-primary w-100">登录</button>
                </form>
                <p class="mt-3 text-center">还没有账号?<a href="{{ url_for('register') }}">注册</a></p>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>

3.register.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>注册</title>
    <!-- 使用 url_for 生成 CSS 文件的绝对路径 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background-image: url('{{ background_image }}');
            background-size: cover;
            background-repeat: no-repeat;
            background-position: center center;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }

       .card {
            border: none;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            background-color: rgba(255, 255, 255, 0.9);
        }

       .card:hover {
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
        }

       .card-header {
            background-color: #0d6efd;
            color: white;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
        }

       .alert {
            margin-top: 15px;
        }
    </style>
</head>

<body>
    <div class="container d-flex justify-content-center align-items-center vh-100">
        <div class="card w-50">
            <div class="card-header text-center">
                <h2>注册</h2>
            </div>
            <div class="card-body">
                {% if error %}
                <div class="alert alert-danger" role="alert">
                    {{ error }}
                </div>
                {% endif %}
                {% if success %}
                <div class="alert alert-success" role="alert">
                    {{ success }}
                </div>
                {% endif %}
                <form method="post">
                    <div class="mb-3">
                        <label for="username" class="form-label">用户名:</label>
                        <input type="text" id="username" name="username" class="form-control" required>
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">密码:</label>
                        <input type="password" id="password" name="password" class="form-control" required>
                    </div>
                    <button type="submit" class="btn btn-primary w-100">注册</button>
                </form>
                <p class="mt-3 text-center">已有账号?<a href="{{ url_for('login') }}">登录</a></p>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>


http://www.kler.cn/a/600605.html

相关文章:

  • ANYmal Parkour: Learning Agile Navigation for Quadrupedal Robots
  • 投sci论文自己查重方法
  • wordpress主题开发框架(灵狐框架),开发文档使用教程
  • 在K8S中使用ArgoCD做持续部署
  • 云原生CI/CD | Argo CD 详细介绍 (一)
  • 在本地Windows机器加载大模型并生成内容
  • Thales靶机攻略
  • HTB 笔记 | SQL 注入基础 + 实操小练习 P2
  • 【从零实现Json-Rpc框架】- 第三方库介绍 - fature篇
  • vue2拦截器 拦截后端返回的数据,并判断是否需要登录
  • MCP协议生态重构AI开发范式:从工具碎片化到系统整合的革命性跨越
  • 【C++11】智能指针:std::shared_ptr
  • MySQL基础语法
  • 文字也能生成视频?【蓝耘实践】:通义万相2.1文生视频
  • cursor安装
  • 生成式媒介革命已至,搜索如何借力DeepSeek破局?
  • DeepSeek加持Excel,探索办公自动化的无限可能
  • Deepseek API+Python 测试用例一键生成与导出 V1.0.3
  • Julia语言的二进制与编码
  • 画秒杀系统流程图