0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[ログイン機能] テストユーザー作り、ログイン

Last updated at Posted at 2025-04-27

いるもん

準備
pip install flask flask-wtf flask-login flask-bcrypt email_validator

前提条件

テストユーザー作りログインしないと、ログインできない

新規登録画面でユーザー作りログインしたら、ログイン❌

テストユーザー作成 (全部コマンド)

flask shell
from app import db, User
from werkzeug.security import generate_password_hash

# 新しいユーザーを作成
username = 'test'
password = 'password'  # 任意のパスワード
hashed_pw = generate_password_hash(password)

new_user = User(username=username, password=hashed_pw)
db.session.add(new_user)
db.session.commit()

print(f"User '{username}' created successfully!")

exit()

サーバー再起動

flask run

テストユーザー   "test" とpw "password"でログイン

今のテスト(ログイン用ユーザー)

 user : testuser

 pw : testpassword

[in 新規登録画面]ログインしてたら、マイページへ行かせる

from flask_login import login_required, current_user

@app.route("/register", methods=["GET", "POST"])
@login_required  # ログインしているユーザーがアクセスできないように
def register():
    if current_user.is_authenticated:
        flash('既にログインしてんじゃん.', 'warning')
        return redirect(url_for('mypage')) 

既に会員登録されてたら、別の画面にリダイレクトさせる

form = RegisterForm()
    if form.validate_on_submit():
        existing_user = User.query.filter_by(username=form.username.data).first()
        if existing_user:
            flash('Username already exists.', 'danger')
            return redirect(url_for('リダイレクトさせたいpage'))

会員登録されてなかったら、パスワードを暗号化し、DBにユーザーとパスワードを追加してmypageへ

hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
        new_user = User(username=form.username.data, password=hashed_pw)
        db.session.add(new_user)
        db.session.commit()
        login_user(new_user)
        flash('Account created successfully!', 'success')
        return redirect(url_for('mypage'))
    return 

お決まり文 + secretKey設定 + login_manager設定

from flask import Flask, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_user, login_required, logout_user, current_user, UserMixin
from flask_bcrypt import Bcrypt
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'

db = SQLAlchemy(app)
# Flask-Loginの設定
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # ログインしていない場合、loginページにリダイレクト
login_manager.login_message = "ログインしてください"  # ログインが必要な場合に表示されるメッセージ
bcrypt = Bcrypt(app)

Userモデル

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(150), unique=True, nullable=False)
    password = db.Column(db.String(150), nullable=False)

secretKey設定

import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

ログインマネージャー設定

db = SQLAlchemy(app)
# Flask-Loginの設定
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # ログインしていない場合、loginページにリダイレクト
login_manager.login_message = "ログインしてください"  # ログインが必要な場合に表示されるメッセージ
bcrypt = Bcrypt(app)

login画面 templates/login.html

<!DOCTYPE html>
<html>
<head><title>Login</title></head>
<body>
    <form method="POST">
        {{ form.hidden_tag() }}
        {{ form.username.label }} {{ form.username() }}<br>
        {{ form.password.label }} {{ form.password() }}<br>
        {{ form.submit() }}
    </form>
</body>
</html>

run.py中身

from app import app, db

if __name__ == "__main__":
    with app.app_context():
        db.create_all()  
        
    app.run(debug=True, use_reloader=True)

mypageに行った時の処理

@app.route("/mypage")
@login_required
def mypage():
    return f"ようこそ、{current_user.id}さん!"

ログアウトさせたら、ログインページへ

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("login"))

LoginFormモデル : ログイん 何使ってログインさせたい?(例 : 名前とパスワード)

class LoginForm(FlaskForm):
    username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired()])
    submit = SubmitField("Login")

RegisterFormモデル : 何使ってユーザー登録させたい?

class RegisterForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=150)])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Register')

ユーザー登録されてたら登録されてるidを見つける

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

[ログイン画面]ユーザー登録されてたらログインさせmypageへ

@app.route("/", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user and bcrypt.check_password_hash(user.password, form.password.data):
            login_user(user)
            flash('ログイン成功!', 'success')
            return redirect(url_for("mypage"))

[in ログイン画面]ユーザー登録dataがない エラーメッセージ表示し、ログイン画面へ

@app.route("/", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()

    else:
        flash('ログイン失敗. 名前とパスワチェックしてね', 'danger')
    return render_template("login.html", form=form)

[in 新規登録画面] 登録されてたらログイン画面へ、登録されてなかったら新規登録画面へ遷移、登録する

app.py
@app.route("/register", methods=["GET", "POST"])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        existing_user = User.query.filter_by(username=form.username.data).first()
        if existing_user:
            flash('Username already exists.', 'danger')
            return redirect(url_for('register'))
        
        hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
        new_user = User(username=form.username.data, password=hashed_pw)
        db.session.add(new_user)
        db.session.commit()
        login_user(new_user)
        flash('アカウント作成成功!', 'success')
        return redirect(url_for('mypage'))
    return render_template("register.html", form=form)

新規登録画面 html

templates/register.html
<!DOCTYPE html>
<html>
<head><title>Register</title></head>
<body>
    <form method="POST">
        {{ form.hidden_tag() }}
        {{ form.username.label }} {{ form.username() }}<br>
        {{ form.password.label }} {{ form.password() }}<br>
        {{ form.submit() }}
    </form>
    <a href="{{ url_for('login') }}">ログインはこちら</a>
</body>
</html>

ユーザー新規登録したら、DBからユーザーとパスワードを探し、パスワードとユーザーを一致させmypageへ行かせる or ログインできなかったらエラー表示

if form.validate_on_submit():
    user = User.query.filter_by(username=form.username.data).first()
    if user and bcrypt.check_password_hash(user.password, form.password.data):
        login_user(user)
        return redirect(url_for("mypage"))
    else:
        flash('Login failed. Check your username and password.', 'danger')

DBからデータ探す

User.query.filter_by(username=form.username.data).first()

ログインさせてる人にのみ、させたい処理 "@login_required"

ログインさせてる人にのみ、maypage表示
@app.route("/mypage")
@login_required
def mypage():
    return f"ようこそ、{current_user.username}さん!"

password暗号化失敗エラー (テストユーザー作ってログイン時)

ValueError: Invalid salt
Form submitted successfully!
[2025-04-27 22:59:28,701] ERROR in app: Exception on / [POST]
Traceback (most recent call last):
  File "/Users/chomechomesuke/.pyenv/versions/3.13.1/lib/python3.13/site-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/chomechomesuke/.pyenv/versions/3.13.1/lib/python3.13/site-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/chomechomesuke/.pyenv/versions/3.13.1/lib/python3.13/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/chomechomesuke/.pyenv/versions/3.13.1/lib/python3.13/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/p/app/app.py", line 50, in login
    if user and bcrypt.check_password_hash(user.password, form.password.data):
                ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chomechomesuke/.pyenv/versions/3.13.1/lib/python3.13/site-packages/flask_bcrypt.py", line 225, in check_password_hash
    return hmac.compare_digest(bcrypt.hashpw(password, pw_hash), pw_hash)
                               ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
ValueError: Invalid salt

パスワ暗号化失敗エラー解決策 (Valuseerror)

flask shell

from app import app, db, User, bcrypt

app.app_context().push()

db.create_all()

username = 'testuser'  
password = 'testpassword'  

hashed_pw = bcrypt.generate_password_hash(password).decode('utf-8')

email = 'test@example.com'
email_verified = False

new_user = User(username=username, password=hashed_pw, email=email, email_verified=email_verified)

db.session.add(new_user)
db.session.commit()


exit()

サーバー再起動

[テストユーザー作成時]emailにnull制約つけてて、emailなしで作ろうとしたらエラー

スクリーンショット 2025-04-30 13.03.51.png

with app.app_context():コマンドがないよ

スクリーンショット 2025-04-30 13.25.09.png

email_verified = Falseを'False'にしてるとエラーに

スクリーンショット 2025-04-30 13.40.44.png

コマンド入力ミスが治ってないよエラー

sqlalchemy.exc.PendingRollbackError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (builtins.TypeError) Not a boolean value: 'False'
[SQL: INSERT INTO user (username, email, password, email_verified) VALUES (?, ?, ?, ?)]
[parameters: [{'password': '$2b$12$1iytbHfDhQ0sxXoSZPO7re0QRh1qNociHMTInjHM0V82pq7C1acCC', 'email_verified': 'False', 'username': 'testuser', 'email': 'test@example.com'}]] (Background on this error at: https://sqlalche.me/e/20/7s2a)

コマンド入力ミスが治ってないよエラ-解決策

db.session.rollback()

テーブルないよエラー

cursor.execute(statement, parameters)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: INSERT INTO user (username, email, password, email_verified) VALUES (?, ?, ?, ?)]
[parameters: ('testuser', 'test@example.com', '$2b$12$VoDrv77qG2PTF1NqV1adm.qtvh1r5bh2yy2Jb7gFE6/0visbAuPH2', 0)]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?