每90天更改一次密码的系统——前后端数据交互过程及代码实战


在设计一个要求用户每90天更改一次密码的系统时,后端的设计需要包括以下几个关键点:如何判断密码是否需要更改、如何告知前端、如何处理密码的更新请求。

1. 数据存储设计

后端需要在数据库中存储用户密码以及密码的最后修改时间。这可以通过在用户表中添加两个字段来实现:

  • password: 存储用户的哈希密码。
  • password_last_changed: 记录密码上次修改的时间,使用时间戳或日期格式。

例如,数据库中的用户表可能如下:

CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(255),
    password_last_changed TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    -- 其他用户信息字段
);

2. 前端获取是否需要更改密码的判断

在用户登录时,后端会检查密码的最后修改时间,如果距离当前时间超过了 90 天,后端会返回一个标志,提示前端要求用户更改密码。后端还可以在每次用户登录时进行检查。

2.1接口设计:/api/login/api/check-password-status

2.1.1 请求:
POST /api/login
{
  "username": "user123",
  "password": "password123"
}
2.1.2 响应:

如果用户成功登录,但密码已经过期,后端返回如下信息:

{
  "status": "success",
  "password_change_required": true,
  "message": "Your password has expired and needs to be changed."
}

如果密码未过期:

{
  "status": "success",
  "password_change_required": false,
  "message": "Login successful."
}
2.1.3 逻辑:
  • 后端根据登录请求进行身份验证。
  • 检查 password_last_changed 字段,计算距离当前时间的天数。
  • 如果超过 90 天,返回 password_change_required: true,并提示用户修改密码。

3. 密码更改接口设计

如果用户的密码已过期,前端会引导用户到密码更改页面。后端需要一个 API 接口来处理密码更新请求。

3.1 接口设计:/api/change-password

3.1.1 请求:
POST /api/change-password
{
  "userId": 123,
  "old_password": "oldPassword123",
  "new_password": "newPassword456"
}
3.1.2 响应:
{
  "status": "success",
  "message": "Password changed successfully."
}
3.1.3 逻辑:
  • 验证用户的身份和旧密码是否正确。
  • 检查新密码是否满足密码复杂性要求(如长度、特殊字符等)。
  • 如果验证通过,更新用户的密码,将 password_last_changed 字段更新为当前时间。
  • 如果密码更新成功,返回成功状态。
3.1.4 密码更新过程中的注意事项:
  • 密码在传输过程中应进行加密(通过 HTTPS)。
  • 后端应对新密码进行哈希处理(如使用 bcrypt),然后存储。
  • 防止弱密码、与旧密码重复等。

4. 额外的安全措施

  • 邮件提醒:在密码即将过期时(如过期前7天),可以发送邮件提醒用户更新密码。
  • 失败登录锁定:如果用户尝试用旧密码登录超过一定次数(例如5次),可以暂时锁定账户,防止暴力破解。
  • 多因素认证 (MFA):为敏感操作(如更改密码)增加多因素验证(如短信或邮件验证码)。

5. 接口的整体流程

  1. 登录请求

    • 用户提交用户名和密码。
    • 后端验证用户名和密码是否匹配,并检查密码的最后修改时间。
    • 如果密码超过 90 天没有修改,返回 password_change_requiredtrue
  2. 修改密码请求

    • 用户在前端收到需要更改密码的提示后,输入旧密码和新密码。
    • 后端验证旧密码,并将新密码保存到数据库,同时更新密码的修改时间。

通过这样的设计,后端能够有效管理密码的过期时间,并通过API接口与前端进行信息交换,确保用户在90天内及时更新密码,保障系统安全。

6.代码实战

下面是基于 Python(使用 Flask 框架)实现的后端代码示例,分别展示前后端如何处理“每 90 天更改一次密码”的逻辑。使用 Flask 框架作为后端,SQLAlchemy 作为 ORM。

6.1 后端:Flask + SQLAlchemy

6.1.1 数据库模型

我们首先定义用户模型 User,包括存储用户的密码哈希和密码最后修改的时间字段。

from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'
    
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)
    password_last_changed = db.Column(db.DateTime, default=datetime.utcnow)
    
    def set_password(self, password):
        """哈希处理并存储密码"""
        self.password_hash = generate_password_hash(password)
        self.password_last_changed = datetime.utcnow()

    def check_password(self, password):
        """验证密码"""
        return check_password_hash(self.password_hash, password)
6.1.2 登录逻辑:检查密码是否需要更新

后端检查用户登录时,判断密码是否需要更新,并返回相应的标志给前端。

from flask import Flask, request, jsonify
from datetime import datetime, timedelta

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db.init_app(app)

PASSWORD_EXPIRY_DAYS = 90  # 密码过期时间为90天

@app.route('/api/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    # 查找用户
    user = User.query.filter_by(username=username).first()
    if not user or not user.check_password(password):
        return jsonify({"status": "error", "message": "Invalid credentials"}), 401

    # 检查密码是否超过90天
    password_age = (datetime.utcnow() - user.password_last_changed).days
    password_change_required = password_age > PASSWORD_EXPIRY_DAYS

    return jsonify({
        "status": "success",
        "password_change_required": password_change_required,
        "message": "Login successful" if not password_change_required else "Password expired, please change your password."
    })

6.1.3 密码更改接口

当前端收到密码过期的提示时,用户输入新密码,后端处理密码更新的逻辑。

@app.route('/api/change-password', methods=['POST'])
def change_password():
    data = request.json
    user_id = data.get('userId')
    old_password = data.get('old_password')
    new_password = data.get('new_password')
    
    # 查找用户
    user = User.query.get(user_id)
    if not user or not user.check_password(old_password):
        return jsonify({"status": "error", "message": "Old password is incorrect"}), 401

    # 检查新密码是否符合规则,可以加入密码复杂性校验逻辑
    if len(new_password) < 8:
        return jsonify({"status": "error", "message": "New password must be at least 8 characters long"}), 400

    # 更新密码和最后修改时间
    user.set_password(new_password)
    db.session.commit()

    return jsonify({"status": "success", "message": "Password changed successfully"})

6.1.4 辅助函数

这些辅助函数用于密码的设置和校验。我们已经在模型中通过 set_passwordcheck_password 进行了密码的哈希处理和校验。

from werkzeug.security import generate_password_hash, check_password_hash

# 生成哈希密码
def generate_hash(password):
    return generate_password_hash(password)

# 校验哈希密码
def verify_password(stored_password_hash, password):
    return check_password_hash(stored_password_hash, password)

6.2 前端(假设使用 HTML + JavaScript)

6.2.1 登录页面逻辑

当用户登录时,前端会检查返回的 password_change_required 字段,决定是否提示用户更改密码。

async function login() {
    const username = document.getElementById("username").value;
    const password = document.getElementById("password").value;

    const response = await fetch('/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password })
    });

    const data = await response.json();
    
    if (data.status === "success") {
        if (data.password_change_required) {
            alert("Your password has expired. Please change your password.");
            // 跳转到更改密码页面
            window.location.href = "/change-password.html";
        } else {
            alert("Login successful");
            // 跳转到主页
            window.location.href = "/home.html";
        }
    } else {
        alert(data.message);
    }
}
6.2.2 更改密码页面逻辑

用户进入更改密码页面后,前端会调用后端的 /api/change-password 接口来更新密码。

async function changePassword() {
    const userId = localStorage.getItem('userId'); // 假设用户ID存储在 localStorage 中
    const oldPassword = document.getElementById("old_password").value;
    const newPassword = document.getElementById("new_password").value;

    const response = await fetch('/api/change-password', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            userId: userId,
            old_password: oldPassword,
            new_password: newPassword
        })
    });

    const data = await response.json();
    
    if (data.status === "success") {
        alert("Password changed successfully");
        // 跳转到登录页面
        window.location.href = "/login.html";
    } else {
        alert(data.message);
    }
}

6.3 逻辑总结

  1. 用户登录时,后端会检查密码是否过期(90 天),并通过 password_change_required 标志告知前端。
  2. 如果密码过期,前端会跳转到密码更改页面,用户输入旧密码和新密码,后端验证并更新密码及 password_last_changed 字段。
  3. 整个流程中确保密码哈希存储、前后端通讯的安全性(如使用 HTTPS)。
Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今晚务必早点睡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值