Flask-Login Authentication Fails After Successful Login

33 Views Asked by At

I am building a web application using Flask, Flask-Login for authentication, and Flask-SQLAlchemy for ORM. I've implemented user registration, login, and email confirmation features. The user login process seems to work as the "user logged in" message appears in the logs, but immediately after redirecting to the home page, the user is considered not authenticated. This issue persists even though the user successfully logs in with correct credentials.

Here's a simplified version of my setup:

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True, nullable=False)
    profile_image = db.Column(db.String(255), nullable=True, default='default.jpg')  # Путь до фотографии пользователя
    email = db.Column(db.String(120), index=True, unique=True, nullable=False)
    email_confirmed = db.Column(db.Boolean, default=False)
    confirmation_code = db.Column(db.String(64), nullable=True)
    confirmation_sent_at = db.Column(db.DateTime, nullable=True)
    password_hash = db.Column(db.String(128))
    phone = db.Column(db.String(20), unique=True, nullable=False)
    first_name = db.Column(db.String(64), nullable=False)
    last_name = db.Column(db.String(64), nullable=False)
    date_of_birth = db.Column(db.Date)
    gender = db.Column(db.String(10))
    address = db.Column(db.String(255))
    is_active = db.Column(db.Boolean, default=True)
    role = db.Column(db.String(64), default='user')
    login_attempts = db.Column(db.Integer, default=0)
    lock_until = db.Column(db.DateTime, nullable=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    
    # Добавляем связь с курсами через таблицу purchases
    courses = db.relationship('Course', secondary=purchases, lazy='subquery',
                              backref=db.backref('users', lazy=True))

    def __repr__(self):
        return f'<User {self.username}>'

    def set_password(self, password):
        password_bytes = password.encode('utf-8')
        salt = bcrypt.gensalt()
        self.password_hash = bcrypt.hashpw(password_bytes, salt).decode('utf-8')

    def check_password(self, password):
        password_bytes = password.encode('utf-8')
        return bcrypt.checkpw(password_bytes, self.password_hash.encode('utf-8'))
    
    
    def increment_login_attempts(self):
        self.login_attempts += 1
        db.session.commit()

    def reset_login_attempts(self):
        self.login_attempts = 0
        db.session.commit()

    def lock_account(self):
        self.lock_until = datetime.utcnow() + timedelta(minutes=10)  # Блокировка на 10 минут
        db.session.commit()

    def is_account_locked(self):
        return self.lock_until is not None and self.lock_until > datetime.utcnow()

    def activate_user(self):
        self.is_active = True
        db.session.commit()

    def deactivate_user(self):
        self.is_active = False
        db.session.commit()

    def confirm_email(self):
        self.email_confirmed = True
        db.session.commit()

Login route:

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        # Изменение фильтрации пользователя с email на username
        user = User.query.filter_by(username=form.username.data).first()
        if user and not user.is_account_locked():
            if user.check_password(form.password.data):
                if user.email_confirmed:
                    print(f'Пользователь "{user.username}" вошел.')
                    user.reset_login_attempts()  # Сброс количества попыток после успешного входа
                    next_page = request.args.get('next')
                    login_user(user)
                    return redirect(next_page) if next_page else redirect(url_for('index'))
                else:
                    flash('Пожалуйста, подтвердите ваш аккаунт перед входом.', 'warning')
            else:
                user.increment_login_attempts()
                if user.login_attempts >= 10:
                    user.lock_account()
                    flash('Ваш аккаунт временно заблокирован из-за многократных неверных попыток входа.', 'danger')
                else:
                    flash('Неверный логин или пароль.', 'danger')
        else:
            flash('Аккаунт заблокирован. Попробуйте позже.', 'danger')
    return render_template('auth/login.html', title='Вход', form=form)

_init_.py:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_mail import Mail
from app.config import Config
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)

app.secret_key = 'ovrewu5t2utu4orhwergewhirghweorghd87827d283t4h2od4`d8`73nfro'

login_manager = LoginManager()

bcrypt = Bcrypt(app)

login_manager.login_view = 'login'
login_manager.init_app(app)

mail = Mail(app)

from app.auth.routes import *
from app.profile.routes import *

What I've tried:

  • Ensuring the SECRET_KEY is set for the Flask application.
  • Verifying that login_user is called with the correct user object.
  • Checking that the user exists and is active in the database.
  • Looking for any issues related to session management or cookie settings in Flask.
0

There are 0 best solutions below