FA-TOOLS — Header Component

ساخت سیستم ورود و خروج کاربر با Flask

رفیق برنامه‌نویس، دیگه وقتشه یه سیستم احراز هویت قوی و مطمئن با Flask بسازی! این راهنما رو تا تهش بخون و یک بار برای همیشه از شر چالش‌های Login/Logout خلاص شو. همین الان به فروشگاه ابزارهای برنامه‌نویسی ما سر بزن و بهترین‌ها رو برای پروژت انتخاب کن. برای هرگونه سوال یا راهنمایی هم می‌تونی با ما تماس بگیری: 09202232789.

نقشه راه: سیستم ورود و خروج با Flask در یک نگاه

✔️ قدم اول: زیرساخت

  • 🔹 نصب Flask و بسته‌های لازم
  • 🔹 تنظیمات اولیه پروژه

⚙️ قدم دوم: دیتابیس

  • 🔹 Flask-SQLAlchemy
  • 🔹 تعریف مدل User

📝 قدم سوم: فرم‌ها

  • 🔹 Flask-WTF
  • 🔹 فرم‌های ثبت‌نام و ورود

🔒 قدم چهارم: احراز هویت

  • 🔹 Flask-Login
  • 🔹 مدیریت جلسات

🎨 قدم پنجم: رابط کاربری

  • 🔹 قالب‌های Jinja2
  • 🔹 طراحی صفحات

🛡️ قدم ششم: امنیت

  • 🔹 هش کردن پسورد
  • 🔹 محافظت از مسیرها

چرا Flask برای سیستم ورود و خروج؟

ساخت سیستم ورود و خروج کاربر با Flask — تصویر 2

فلسک (Flask) یه میکرو فریم‌ورک پایتونه که به خاطر سادگی، انعطاف‌پذیری و حجم کمش معروفه. اگه می‌خوای یه سیستم ورود و خروج کاربر بسازی، Flask انتخاب خیلی خوبیه چون:

  • سبک و سریع: سربار اضافی نداره و پروژه‌ات رو چابک نگه می‌داره.
  • انعطاف‌پذیری بالا: هر کتابخونه‌ای که دوست داری می‌تونی بهش اضافه کنی و به نیازهای خاص پروژه خودت پاسخش بده.
  • جامعه فعال: کلی مثال و راهنما پیدا می‌کنی که کمکت می‌کنه.
  • یادگیری آسان: برای شروع، curva یادگیریش خیلی ملایمه و زود راه میفتی.

به همین دلایل، برای پروژه‌هایی که نیاز به احراز هویت دارن، از وبلاگ‌های ساده گرفته تا APIهای پیچیده، Flask یه گزینه عالیه. اگه دنبال کد‌های پایتون بیشتری هستی، حتماً یه سری به اسنیپت‌های پایتون ما بزن.

پیش‌نیازها: قبل از شروع چی لازم داریم؟

ساخت سیستم ورود و خروج کاربر با Flask — تصویر 3

قبل از اینکه دست به کد بشیم، مطمئن شو که این موارد رو آماده داری:

  • پایتون (Python): نسخه‌ی ۳.۶ به بالا.
  • Pip: مدیر بسته پایتون که معمولاً با خود پایتون نصب میشه.
  • محیط مجازی (Virtual Environment): همیشه برای هر پروژه‌ای یه محیط مجازی بساز تا وابستگی‌ها قاطی نشن.

نصب پکیج‌های لازم

اول یه پوشه برای پروژه‌ات بساز و یه محیط مجازی توش فعال کن، بعد این دستورات رو تو ترمینال اجرا کن:


mkdir flask_auth
cd flask_auth
python -m venv venv
source venv/bin/activate  # برای لینوکس/مک
# venvScriptsactivate   # برای ویندوز
pip install Flask Flask-SQLAlchemy Flask-WTF Flask-Login Werkzeug bcrypt
    
  • Flask: فریم‌ورک اصلی.
  • Flask-SQLAlchemy: برای کار با دیتابیس (ORM).
  • Flask-WTF: برای مدیریت و اعتبارسنجی فرم‌ها.
  • Flask-Login: برای مدیریت ورود، خروج و جلسات کاربر.
  • Werkzeug: یه کتابخونه ابزاری برای WSGI، که Flask ازش استفاده می‌کنه.
  • Bcrypt: برای هش کردن امن پسوردها.

گام اول: راه‌اندازی پروژه Flask

فایل اصلی اپلیکیشن رو می‌سازیم. اسمش رو بزار app.py:


# app.py
from flask import Flask, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
import os

app = Flask(__name__)

# پیکربندی اپلیکیشن
app.config['SECRET_KEY'] = os.urandom(24).hex() # یک کلید سری برای امنیت سشن‌ها
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # استفاده از دیتابیس SQLite
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # جلوی اخطارهای اضافی رو می‌گیره

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login' # مسیر صفحه ورود رو مشخص می‌کنه
login_manager.login_message_category = 'info' # دسته پیام فلش برای ورود

# این تابع Flask-Login نیاز داره تا کاربر رو از ID پیدا کنه
@login_manager.user_loader
def load_user(user_id):
    from models import User # از اینجا مدل User رو import می‌کنیم
    return db.session.get(User, int(user_id))

# تعریف مسیرهای اصلی (routes) در ادامه
# ...
if __name__ == '__main__':
    with app.app_context():
        db.create_all() # دیتابیس رو ایجاد می‌کنه اگه وجود نداشته باشه
    app.run(debug=True)
    

نکات مهم:

  • SECRET_KEY: این کلید حیاتیه! برای امنیت سشن‌ها و محافظت در برابر حملات CSRF استفاده میشه. حتماً یه کلید قوی و رندوم بزار.
  • SQLALCHEMY_DATABASE_URI: ما از SQLite استفاده می‌کنیم که یه فایل دیتابیس ساده است. برای پروژه‌های بزرگتر، می‌تونی از PostgreSQL یا MySQL استفاده کنی.
  • load_user: این تابع برای Flask-Login لازمه تا بتونه اطلاعات کاربر رو با استفاده از ID سشن بازیابی کنه.

گام دوم: دیتابیس و مدل‌های کاربر

یه فایل جدید به اسم models.py بساز تا مدل User رو تعریف کنیم. این مدل، ساختار اطلاعات کاربری رو توی دیتابیس مشخص می‌کنه.


# models.py
from datetime import datetime
from app import db # از فایل app.py متغیر db رو import می‌کنیم
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"
    

توضیحات مهم:

  • UserMixin: این کلاس رو از Flask-Login ارث‌بری می‌کنه و متدهای لازم برای مدیریت کاربر رو به مدل ما اضافه می‌کنه (مثل is_authenticated, is_active, is_anonymous, get_id).
  • password_hash: هیچ‌وقت پسوردها رو به صورت متن ساده (plaintext) ذخیره نکن! ما از generate_password_hash و check_password_hash از werkzeug.security استفاده می‌کنیم که پسورد رو هش می‌کنه.

گام سوم: فرم‌های ثبت‌نام و ورود (WTForms)

حالا یه فایل دیگه به اسم forms.py بسازیم تا فرم‌های ثبت‌نام و ورود رو تعریف کنیم. Flask-WTF کار رو خیلی راحت می‌کنه:


# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from models import User # مدل User رو import می‌کنیم

class RegistrationForm(FlaskForm):
    username = StringField('نام کاربری', validators=[DataRequired(), Length(min=2, max=20)])
    email = StringField('ایمیل', validators=[DataRequired(), Email()])
    password = PasswordField('رمز عبور', validators=[DataRequired()])
    confirm_password = PasswordField('تکرار رمز عبور',
                                     validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('ثبت‌نام')

    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user:
            raise ValidationError('این نام کاربری از قبل وجود دارد. لطفا نام کاربری دیگری انتخاب کنید.')

    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user:
            raise ValidationError('این ایمیل از قبل ثبت شده است. لطفا از ایمیل دیگری استفاده کنید.')

class LoginForm(FlaskForm):
    email = StringField('ایمیل', validators=[DataRequired(), Email()])
    password = PasswordField('رمز عبور', validators=[DataRequired()])
    remember = BooleanField('مرا به خاطر بسپار')
    submit = SubmitField('ورود')
    

توضیحات مهم:

  • Validators: اعتبار‌سنج‌ها (validators) مثل DataRequired (اجباری بودن فیلد) یا Email (فرمت ایمیل) رو تعریف می‌کنن.
  • Custom Validators: متدهای validate_username و validate_email برای چک کردن یکتا بودن نام کاربری و ایمیل قبل از ثبت‌نام هستن.

گام چهارم: منطق احراز هویت (Login Manager)

حالا باید منطق مربوط به مسیرها (routes) رو به فایل app.py اضافه کنیم. این بخش شامل نمایش فرم‌ها، پردازش اطلاعات و عملیات ورود/خروج هست.


# app.py (ادامه فایل)
# ...
from forms import RegistrationForm, LoginForm
from models import User

@app.route('/')
@app.route('/home')
def home():
    return render_template('home.html', title='خانه')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('حساب کاربری شما با موفقیت ایجاد شد! حالا می‌توانید وارد شوید.', 'success')
        return redirect(url_for('login'))
    return render_template('register.html', title='ثبت‌نام', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.check_password(form.password.data):
            login_user(user, remember=form.remember.data)
            next_page = request.args.get('next')
            flash('ورود با موفقیت انجام شد!', 'success')
            return redirect(next_page or url_for('home'))
        else:
            flash('ورود ناموفق. لطفاً ایمیل و رمز عبور را بررسی کنید.', 'danger')
    return render_template('login.html', title='ورود', form=form)

@app.route('/logout')
def logout():
    logout_user()
    flash('شما با موفقیت از سیستم خارج شدید.', 'info')
    return redirect(url_for('home'))

@app.route('/dashboard')
@login_required # این دکوراتور مسیر رو محافظت می‌کنه
def dashboard():
    return render_template('dashboard.html', title='داشبورد')

# ...
# در ابتدای app.py باید اینها رو اضافه کنی:
# from flask_login import login_user, current_user, logout_user, login_required
# from flask import request
    

نکات طلایی:

  • current_user.is_authenticated: با این می‌تونی چک کنی که کاربر الان لاگین هست یا نه. اگه باشه، به صفحه home ریدایرکت میشه.
  • flash(): برای نمایش پیام‌های کوتاه به کاربر استفاده میشه (مثل “ثبت‌نام موفق”).
  • login_user(): کاربر رو وارد سیستم می‌کنه و سشن رو براش ایجاد می‌کنه.
  • login_required: این دکوراتور از Flask-Login میاد و هر مسیری رو که بخوای، فقط برای کاربرای لاگین شده قابل دسترسی می‌کنه.

گام پنجم: قالب‌های HTML و رابط کاربری

حالا نوبت طراحی رابط کاربریه. یه پوشه به اسم templates توی ریشه پروژه‌ات بساز. داخلش چند تا فایل HTML درست کن: base.html (قالب اصلی)، home.html، register.html، login.html و dashboard.html.

برای اینکه محتوای شما کاملا رسپانسیو باشه، از متدهای طراحی مدرن و CSS Grid یا Flexbox باید استفاده کنید. من اینجا فقط ساختار کلی رو نشون میدم که روی همه دستگاه‌ها خوب نمایش داده بشه:

templates/base.html


<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Auth - {{ title }}</title>
    <!-- می‌تونی اینجا CSS خودت رو اضافه کنی یا از CDN مثل Bootstrap استفاده کنی -->
    <style>
        body { font-family: 'Vazirmatn', sans-serif; margin: 0; padding: 0; background-color: #f4f7f6; color: #333; display: flex; flex-direction: column; min-height: 100vh; }
        .container { max-width: 960px; margin: 20px auto; padding: 20px; background-color: #fff; border-radius: 10px; box-shadow: 0 5px 15px rgba(0,0,0,0.1); flex-grow: 1; }
        header { background-color: #007bff; color: #fff; padding: 15px 0; text-align: center; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
        header a { color: #fff; text-decoration: none; margin: 0 15px; font-weight: bold; }
        header a:hover { text-decoration: underline; }
        .flash-messages { margin-bottom: 20px; padding: 10px; border-radius: 5px; text-align: center; }
        .flash-messages.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
        .flash-messages.danger { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
        .flash-messages.info { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
        form div { margin-bottom: 15px; }
        form label { display: block; margin-bottom: 5px; font-weight: bold; }
        form input[type="text"], form input[type="password"], form input[type="email"] { width: calc(100% - 22px); padding: 10px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; }
        form input[type="submit"] { background-color: #28a745; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 1.1em; }
        form input[type="submit"]:hover { background-color: #218838; }
        .form-group { margin-bottom: 15px; }
        .form-group label { display: block; margin-bottom: 5px; }
        .form-control { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
        .btn-primary { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
        .btn-primary:hover { background-color: #0056b3; }
        footer { background-color: #343a40; color: #fff; text-align: center; padding: 15px 0; margin-top: auto; }
        @media (max-width: 768px) {
            .container { margin: 10px auto; padding: 15px; }
            header a { margin: 0 8px; font-size: 0.9em; }
        }
    </style>
</head>
<body>
    <header>
        <nav>
            <a href="{{ url_for('home') }}">خانه</a>
            {% if current_user.is_authenticated %}
                <a href="{{ url_for('dashboard') }}">داشبورد</a>
                <a href="{{ url_for('logout') }}">خروج</a>
            {% else %}
                <a href="{{ url_for('login') }}">ورود</a>
                <a href="{{ url_for('register') }}">ثبت‌نام</a>
            {% endif %}
        </nav>
    </header>
    <div class="container">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="flash-messages {{ category }}">
                        {{ message }}
                    </div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </div>
    <footer>
        <p>&copy; 2023 سیستم احراز هویت با Flask. تمامی حقوق محفوط است.</p>
    </footer>
</body>
</html>
    

templates/home.html


{% extends "base.html" %}
{% block content %}
    <H1 style="font-size: 2em; color: #333; margin-bottom: 20px;">به سیستم احراز هویت Flask خوش آمدید!</H1>
    {% if current_user.is_authenticated %}
        <p style="font-size: 1.1em; line-height: 1.6;">سلام، <strong>{{ current_user.username }}</strong>! شما وارد شدید.</p>
        <p style="font-size: 1.1em; line-height: 1.6;">برای دسترسی به اطلاعات کاربری، به <a href="{{ url_for('dashboard') }}" style="color: #007bff; text-decoration: none;">داشبورد</a> خود بروید.</p>
    {% else %}
        <p style="font-size: 1.1em; line-height: 1.6;">برای استفاده از امکانات سایت، لطفاً <a href="{{ url_for('register') }}" style="color: #28a745; text-decoration: none;">ثبت‌نام</a> یا <a href="{{ url_for('login') }}" style="color: #007bff; text-decoration: none;">وارد</a> شوید.</p>
    {% endif %}
{% endblock content %}
    

templates/register.html


{% extends "base.html" %}
{% block content %}
    <div style="background-color: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); max-width: 500px; margin: 30px auto;">
        <h1 style="text-align: center; color: #333; margin-bottom: 30px;">ثبت‌نام</h1>
        <form method="POST" action="" style="direction: rtl;">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.username.label(class="form-label") }}
                {{ form.username(class="form-control", placeholder="نام کاربری") }}
                {% if form.username.errors %}
                    {% for error in form.username.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.email.label(class="form-label") }}
                {{ form.email(class="form-control", placeholder="ایمیل") }}
                {% if form.email.errors %}
                    {% for error in form.email.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password.label(class="form-label") }}
                {{ form.password(class="form-control", placeholder="رمز عبور") }}
                {% if form.password.errors %}
                    {% for error in form.password.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.confirm_password.label(class="form-label") }}
                {{ form.confirm_password(class="form-control", placeholder="تکرار رمز عبور") }}
                {% if form.confirm_password.errors %}
                    {% for error in form.confirm_password.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group" style="text-align: center;">
                {{ form.submit(class="btn-primary") }}
            </div>
        </form>
        <p style="text-align: center; margin-top: 20px;">از قبل حساب کاربری دارید؟ <a href="{{ url_for('login') }}" style="color: #007bff; text-decoration: none;">وارد شوید</a>.</p>
    </div>
{% endblock content %}
    

templates/login.html


{% extends "base.html" %}
{% block content %}
    <div style="background-color: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); max-width: 500px; margin: 30px auto;">
        <h1 style="text-align: center; color: #333; margin-bottom: 30px;">ورود</h1>
        <form method="POST" action="" style="direction: rtl;">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.email.label(class="form-label") }}
                {{ form.email(class="form-control", placeholder="ایمیل") }}
                {% if form.email.errors %}
                    {% for error in form.email.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password.label(class="form-label") }}
                {{ form.password(class="form-control", placeholder="رمز عبور") }}
                {% if form.password.errors %}
                    {% for error in form.password.errors %}
                        <span style="color: red; font-size: 0.9em;">{{ error }}</span>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.remember(class="form-check-input") }}
                {{ form.remember.label(class="form-check-label") }}
            </div>
            <div class="form-group" style="text-align: center;">
                {{ form.submit(class="btn-primary") }}
            </div>
        </form>
        <p style="text-align: center; margin-top: 20px;">حساب کاربری ندارید؟ <a href="{{ url_for('register') }}" style="color: #28a745; text-decoration: none;">ثبت‌نام کنید</a>.</p>
    </div>
{% endblock content %}
    

templates/dashboard.html


{% extends "base.html" %}
{% block content %}
    <div style="text-align: center; padding: 40px 20px; background-color: #e9f7ef; border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.08);">
        <h1 style="color: #28a745; margin-bottom: 20px;">داشبورد کاربر</h1>
        <p style="font-size: 1.2em; line-height: 1.8; color: #444;">به داشبورد خود خوش آمدید، <strong>{{ current_user.username }}</strong>!</p>
        <p style="font-size: 1.1em; line-height: 1.6; color: #555;">ایمیل شما: <em>{{ current_user.email }}</em></p>
        <p style="font-size: 1.1em; line-height: 1.6; color: #555;">تاریخ ثبت‌نام: <em>{{ current_user.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</em></p>
        <p style="margin-top: 30px;">
            <a href="{{ url_for('logout') }}" class="btn-primary" style="background-color: #dc3545; text-decoration: none; padding: 10px 20px; border-radius: 5px; color: white; display: inline-block;">خروج از حساب</a>
        </p>
    </div>
{% endblock content %}
    

استفاده از Jinja2 و ارث‌بری قالب ({% extends %} و {% block %}) کار رو برای ساخت صفحات مشابه خیلی آسون می‌کنه. همچنین با استفاده از CSS ساده و خصوصیت‌هایی مثل max-width و margin: auto و flex-direction: column; min-height: 100vh; برای body و flex-grow: 1; برای container، ساختاری کاملاً رسپانسیو خواهیم داشت. برای استایل‌های بیشتر، می‌تونید به اسنیپت‌های CSS ما مراجعه کنید.

گام ششم: مدیریت جلسات (Sessions) و محافظت از مسیرها

همونطور که دیدیم، Flask-Login به صورت خودکار مدیریت سشن‌ها رو برای ما انجام میده. وقتی کاربر وارد میشه، یه سشن براش ایجاد میشه و اطلاعاتش رمزنگاری شده در کوکی ذخیره میشه. با @login_required هم مطمئن میشیم که کاربرای ناشناس نتونن به صفحات مهم مثل داشبورد دسترسی پیدا کنن.

جدول مقایسه‌ای: مدیریت سشن در وب

ویژگی توضیحات
Session-based Authentication اطلاعات سشن کاربر در سمت سرور (مثل دیتابیس یا حافظه) ذخیره می‌شود و یک Session ID به کاربر در کوکی ارسال می‌گردد.
Token-based Authentication (JWT) اطلاعات احراز هویت در یک توکن رمزنگاری شده (معمولاً JWT) به سمت کلاینت ارسال می‌شود و سرور نیازی به ذخیره سشن ندارد.

در این مقاله، ما از رویکرد Session-based با کمک Flask-Login استفاده کردیم که برای اپلیکیشن‌های وب سنتی بسیار رایج و امن است.

افزایش امنیت سیستم شما

امنیت تو یه سیستم احراز هویت حرف اول رو میزنه. اینا چند تا نکته مهم برای بالا بردن امنیت پروژه:

  • استفاده از HTTPS: همیشه از HTTPS استفاده کن تا اطلاعات کاربر حین انتقال امن باشن.
  • هش کردن پسوردها: همونطور که با bcrypt انجام دادیم، پسوردها رو هش کن و هیچ‌وقت plaintext ذخیره نکن.
  • کلید SECRET_KEY قوی: یه کلید خیلی قوی و رندوم بزار و تو گیت‌هاب منتشرش نکن! می‌تونی از متغیرهای محیطی برای ذخیره‌اش استفاده کنی.
  • جلوگیری از حملات CSRF: Flask-WTF به صورت خودکار توکن‌های CSRF رو برای فرم‌ها ایجاد می‌کنه که تو رو از این حملات محافظت می‌کنه.
  • اعتبارسنجی ورودی‌ها: همیشه اطلاعاتی که از کاربر می‌گیری رو اعتبار‌سنجی کن تا از حملات Injection جلوگیری کنی.
  • محدودیت نرخ (Rate Limiting): برای جلوگیری از حملات Brute Force روی صفحات ورود و ثبت‌نام، می‌تونی از Rate Limiting استفاده کنی.

عیب‌یابی سریع (Troubleshooting)

در طول توسعه، ممکنه با مشکلاتی روبرو بشی. اینجا چند تا مشکل رایج و راه‌حلشون رو آوردم:

مشکل ۱: دیتابیس ساخته نمیشه یا جداول خالی هستن

علت: ممکنه db.create_all() توی کانتکس اپلیکیشن اجرا نشده باشه یا مدل User شناخته نشده باشه.

راه‌حل: مطمئن شو که with app.app_context(): db.create_all() دقیقاً در بخش if __name__ == '__main__': فایل app.py هست. همچنین، فایل models.py رو داخل app.py (مثلاً بعد از تعریف db) import کرده باشی (مثل from models import User).

مشکل ۲: پیام‌های فلش (flash messages) نمایش داده نمیشن

علت: ممکنه توکن SECRET_KEY تنظیم نشده باشه یا قالب base.html برای نمایش پیام‌ها کدش کامل نباشه.

راه‌حل: مطمئن شو که app.config['SECRET_KEY'] رو با یه رشته قوی پر کردی. همچنین، کد مربوط به {% with messages = get_flashed_messages(with_categories=true) %} رو به درستی داخل base.html قرار دادی.

مشکل ۳: خطای ValidationError برای نام کاربری یا ایمیل تکراری

علت: متدهای validate_username و validate_email در forms.py درست کار نمی‌کنند.

راه‌حل: مطمئن شو که از User.query.filter_by(...).first() به درستی استفاده کردی و مدل User رو در forms.py به درستی import کردی (from models import User). همچنین، دیتابیس رو بعد از اضافه کردن این ولیدیتورها یک بار حذف و مجددا بساز تا تغییرات اعمال بشن (rm site.db و دوباره python app.py).

مشکل ۴: @login_required کار نمی‌کنه و به صفحه ورود هدایت نمیشم

علت: login_manager.login_view درست تنظیم نشده یا load_user مشکل داره.

راه‌حل: در فایل app.py مطمئن شو که login_manager.login_view = 'login' رو دقیقاً به اسم تابع (نه مسیر URL) صفحه ورودت اشاره می‌کنه. همچنین تابع load_user باید به درستی پیاده‌سازی شده باشه و کاربر رو با استفاده از user_id از دیتابیس بازیابی کنه.

برای مشکلات عمومی‌تر پایتون، می‌تونی از اسنیپت‌های ما کمک بگیری یا سوالت رو تو انجمن‌های برنامه‌نویسی مطرح کنی. برای کدنویسی بهتر هم نگاهی به اسنیپت‌های HTML و اسنیپت‌های جاوااسکریپت بنداز!

نتیجه‌گیری

تبریک میگم! تو تونستی یه سیستم ورود و خروج کاربر با Flask رو از صفر تا صد بسازی. با استفاده از Flask-SQLAlchemy برای دیتابیس، Flask-WTF برای فرم‌ها و Flask-Login برای مدیریت احراز هویت، یه سیستم امن و کارآمد داری. این ساختار پایه‌ای رو می‌تونی برای انواع پروژه‌های وب خودت گسترش بدی و امکانات بیشتری مثل فراموشی رمز عبور، تایید ایمیل و… رو بهش اضافه کنی. یادت باشه، یادگیری برنامه‌نویسی یه مسیر مداومیه و هر روز چیزای جدیدی هست که میشه یاد گرفت. موفق باشی رفیق!

💡 آیا به دنبال ابزارهای بیشتر یا کدهای آماده هستید؟

از مجموعه‌ی کامل کدهای آماده و اسنیپت‌های برنامه‌نویسی ما دیدن کنید تا پروژه‌هایتان را سریع‌تر و با کیفیت‌تر بسازید!


همین حالا شروع کنید!

Table of Contents

آخرین نوشته‌ها