實現了用戶密碼的加密,代理跳轉到目標網址,不會暴露目標路徑,未登錄的情況下訪問proxy則自動跳轉到登錄頁,使用時需要修改配置項config,登錄注冊頁面背景快速修改,可以實現登錄注冊模塊的快速復用。
1.app.py
from flask import Flask, render_template, request, redirect, url_for, session, Response
import sqlite3
import os
import bcrypt
import requestsapp = 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 = Nonesuccess = Noneif 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 = Noneif 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'] = usernameif remember_me:session.permanent = Truereturn 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>