いるもん
準備
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なしで作ろうとしたらエラー
with app.app_context():コマンドがないよ
email_verified = Falseを'False'にしてるとエラーに
コマンド入力ミスが治ってないよエラー
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)