从零开始:用Flask框架实现一个简单而实用的登录页面

简介

登录验证是私密性较强网页的共同需求,这篇文章提供一个基于FLask的登录验证功能实现。

实现

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
    <link rel="shortcut icon" href="/static/images/favicon.ico">
    <link rel="stylesheet" href="/static/css/login.css">
</head>
<body>
  <div class="login-container">
    <h2>登录</h2>
    <form id="loginForm">
      <div class="input-group">
        <label for="username">用户名:</label>
        <input type="text" id="username" required>
      </div>
      <div class="input-group">
        <label for="password">密码:</label>
        <input type="password" id="password" required>
      </div>
      <button type="submit">登录</button>
      <p id="error-message" style="color: red; display: none;">用户名或密码错误</p>
    </form>
  </div>
  <script src="/static/js/login.js" async></script>
</body>
</html>

登录界面很简单,只有用户名、密码输入框和登录按钮。

CSS

body {
  margin: 0;
  padding: 0;
  height: 100vh;
  background: url('/static/images/background.jpg') no-repeat center center fixed; /* 设置页面背景 */
  background-size: cover;
  font-family: Arial, sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 登录容器 */
.login-container {
  background-color: rgba(255, 255, 255, 0.3); /* 半透明背景 */
  padding: 30px;
  border-radius: 8px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
  width: 100%;
  max-width: 400px;
  text-align: center;
  backdrop-filter: blur(10px); /* 背景模糊效果 */
}

/* 标题样式 */
h2 {
  font-size: 32px;
  color: #697EBF;
  margin-bottom: 20px;
  font-weight: 600;
}

/* 输入框样式 */
.input-group {
  margin-bottom: 15px;
  text-align: left;
}

/* 标签样式 */
label {
  display: block;
  margin-bottom: 5px;
  color: #697EBF;
  /*font-weight: bold;
}

/* 输入框样式 */
input[type="text"], input[type="password"] {
  width: 100%;
  padding: 10px;
  margin-top: 5px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
  box-sizing: border-box;
  transition: all 0.3s ease;
}

/* 输入框聚焦效果 */
input[type="text"]:focus, input[type="password"]:focus {
  border-color: #697EBF;
  outline: none;
  box-shadow: 0 0 8px rgba(76, 175, 80, 0.3);
}

/* 按钮样式 */
button {
  width: 100%;
  padding: 12px;
  background-color: #697EBF;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
}

button:hover {
  background-color: #5a79ba;
}

/* 错误信息 */
#error-message {
  margin-top: 15px;
  font-size: 14px;
  color: red;
  display: none;
  text-align: center;
}

@media (max-width: 768px) {
    .login-container {
      width: 100%;
      max-width: 250px;
    }
    h2 {
      font-size: 24px;
  }
}

CSS样式没什么好说的,依旧是根据自己的需要修改。

JS

document.getElementById('loginForm').addEventListener('submit', function(event) {
  event.preventDefault();  // 防止表单默认提交

  const username = document.getElementById('username').value;
  const password = document.getElementById('password').value;

  // 发送 POST 请求到后端
  fetch('/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ username, password }),
  })
    .then(response => response.json())
    .then(data => {
      if (data.success) {
        window.location.href = '/index';  // 登录成功后的跳转界面
      } else {
        document.getElementById('error-message').style.display = 'block';
      }
    })
    .catch(err => console.error('Error:', err));
});

登录函数获取输入的用户名和密码提交到后端进行验证,如果验证成功则跳转到主界面,如果验证失败则显示错误信息。

后端代码

首先实现login函数;

username = os.environ.get('username')
password = os.environ.get('password')

def generate_encrypted_string(username, password):
    combined_string = username + password
    encrypted_string = hashlib.sha256(combined_string.encode('utf-8')).hexdigest()  # 使用 SHA-256 加密
    return encrypted_string

@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()  # 获取前端发送的JSON数据
    usn = data.get('username')
    pwd = data.get('password')
    hashed = generate_encrypted_string(usn, pwd)
    # 验证用户名和密码
    if hashed == generate_encrypted_string(username, password):
        session['logged_in'] = hashed
        session['login_time'] = datetime.now(timezone.utc)  # 记录登录时间
        return jsonify({'success': True})
    else:
        return jsonify({'success': False, 'message': 'Invalid username or password'})

login函数获取用户名和密码组合的哈希值,并与正确的哈希值进行比对,如果登录成功则在浏览器中保存当前哈希值和登录时间。

需要注意的是,用户名和密码不应该在服务器明文保存,正确的做法是在注册用户时将加密后的哈希值保存到数据库中,登录时可以直接比对。由于笔者的用户名和密码是以环境变量的形式存在的,同样没有明文写入代码中,因此省略了这一部分代码。

接下来实现登录跳转代码;

def check_login():
    if 'logged_in' not in session or not session['logged_in']:
        # 如果没有登录,则重定向到登录页面
        return False
    else:
        logged_in = session['logged_in']
        if logged_in != generate_encrypted_string(username, password):
            return False

    login_time = session.get('login_time')

    if login_time:
        current_time = datetime.now(timezone.utc)  # 使用 UTC 时区的当前时间
        if abs(current_time - login_time) > SESSION_TIMEOUT:
            session.pop('logged_in', None)
            session.pop('login_time', None)
            return False
    return True

@app.route('/')
def home():
    if check_login():
        return redirect(url_for('index'))
    return render_template('login.html')  # 返回登录页面

@app.route('/index', methods=['GET'])
def index():
    # 处理登录逻辑
    if not check_login():
        return redirect(url_for('home'))
    # ……业务逻辑
    pass

check_login函数用于检测用户是否已经登录;home和index都是网站的入口路由,需要在函数头部添加登录逻辑。

最后完成退出登录代码;

@app.route('/logout')
def logout():
    # 注销登录,清除 session
    session.pop('logged_in', None)
    session.pop('login_time', None)
    return redirect(url_for('home'))  # 重定向到登录页面

退出登录的JS代码如下:

function logout() {
    fetch('/logout', {
        method: 'GET',
        credentials: 'same-origin' // 保证请求时带上当前的 session 信息
    })
    .then(response => {
        if (response.ok) {
            window.location.href = '/'; // 重定向到登录页面
        } else {
            alert('退出失败,请稍后再试');
        }
    })
    .catch(error => {
        console.error('退出时发生错误:', error);
        alert('退出失败,请稍后再试');
    });
}

随便找个按钮调用logout函数就可以实现退出登录功能了。


从零开始:用Flask框架实现一个简单而实用的登录页面
https://blog.nasxyz.top/archives/fb9bd38c-0312-49cf-8c2a-cb289bddfbe9
作者
kanochi
发布于
2025年02月09日
更新于
2025年02月09日
许可协议