質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

2071閲覧

コアサーバーでflask-loginの機能が使えない

dabi

総合スコア6

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/04/17 10:56

編集2022/04/21 11:01

flask-loginでappにログイン機能を実装し、ローカル環境ではログインするとうまくいきました。しかし、コアサーバーにそれをアップロードし、そこからログインしようとするとUnauthorizedのエラーが出てしまいます。
また、ブラウザchrome以外だとユーザー新規登録の時にエラーが発生、そしてChromeでもユーザー名などを日本語にするとエラーが起きてしまいます。(ローカルでは、日本語でも問題なく登録できた。)なぜこのようなエラーが出るのかを突き止めたいです。
※追記
index.pyを編集しました。

app─┬─index.py ├─index.cgi ├─.htaccess ├─┬templates┬register.html │ │ ├login.html │ │ └myhome.html │ └static─style.css └─user.db
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /index.cgi/$1 [QSA,L] <Files ~ "\.py$"> deny from all </Files>

index.cgi

1#!/usr/local/bin/python3 2 3from wsgiref.handlers import CGIHandler 4from index import app 5 6CGIHandler().run(app) 7

index.py

1import os 2import random, string 3import math 4from flask import Flask, render_template, request, redirect, url_for, g, session, flash 5from flask_sqlalchemy import SQLAlchemy 6from flask_login import LoginManager, UserMixin, current_user, login_user, login_required, logout_user 7from werkzeug.security import generate_password_hash, check_password_hash 8 9app = Flask(__name__) 10app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///user.db' 11app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 12app.config['SECRET_KEY'] = os.urandom(24) 13db = SQLAlchemy(app) 14 15app.config['UPLOAD_FOLDER'] = 'static/images' 16app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000 17 18login_manager = LoginManager() 19login_manager.init_app(app) 20 21 22 23class User(UserMixin, db.Model): 24 id = db.Column(db.Integer, primary_key=True) 25 username = db.Column(db.String(50)) 26 password = db.Column(db.String(25)) 27 mail = db.Column(db.String(64)) 28 msg = db.Column(db.String(500)) 29 voting = db.Column(db.String(3)) 30 video_query = db.Column(db.String(3)) 31 rep = db.Column(db.Float) 32 star = db.Column(db.Integer) 33 34 def get_id(self): 35 return self.id 36 37 def is_authenticated(self): 38 return True 39 40 def is_anonymous(self): 41 return False 42 43 def is_active(self): 44 return False 45 46class User_mail(UserMixin, db.Model): 47 id = db.Column(db.Integer, primary_key=True) 48 username = db.Column(db.String(50)) 49 mail = db.Column(db.String(64)) 50 51class Vote(UserMixin, db.Model): 52 __tablename__ = "vote" 53 id = db.Column(db.Integer, primary_key=True) 54 voted_mail = db.Column(db.String(64)) 55 vote_mail = db.Column(db.String(64)) 56 57class VideoVote(db.Model): 58 id = db.Column(db.Integer, primary_key=True) 59 video_voted_mail = db.Column(db.String(64)) 60 video_vote_mail = db.Column(db.String(64)) 61 62 63class Hit(db.Model): 64 id = db.Column(db.Integer, primary_key=True) 65 star_mail = db.Column(db.String(64)) 66 hit_mail = db.Column(db.String(64)) 67 hit_id = db.Column(db.String(64)) 68 69class VideoHit(db.Model): 70 id = db.Column(db.Integer, primary_key=True) 71 video_star_mail = db.Column(db.String(64)) 72 video_hit_mail = db.Column(db.String(64)) 73 video_hit_id = db.Column(db.Integer) 74 75class ForRep(db.Model): 76 id = db.Column(db.Integer, primary_key=True) 77 video_star_mail = db.Column(db.String(64)) 78 video_hit_mail = db.Column(db.String(64)) 79 80class GroupVideo(db.Model): 81 id = db.Column(db.Integer, primary_key=True) 82 one = db.Column(db.Integer) 83 two = db.Column(db.Integer) 84 three = db.Column(db.Integer) 85 four = db.Column(db.Integer) 86 five = db.Column(db.Integer) 87 group_id = db.Column(db.Integer) 88 89def randomname(n): 90 randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)] 91 return ''.join(randlst) 92 93db.create_all() 94 95 96@login_manager.user_loader 97def load_user(user_id): 98 return User.query.get(int(user_id)) 99 100@app.route('/') 101def index(): 102 return render_template('index.html') 103 104@app.route('/register', methods=['POST', 'GET']) 105def register(): 106 if request.method == "POST": 107 username = request.form.get('name') 108 password = request.form.get('password') 109 mailaddress = request.form.get('mail') 110 mailg ='@' in mailaddress 111 mailgd = '.' in mailaddress 112 print(mailg) 113 if mailg == False: 114 return redirect('/register_w3') 115 if mailgd == False: 116 return redirect('/register_w3') 117 print(username + ':' + password + ':' + mailaddress) 118 # Userのインスタンスを作成 119 if username == '': 120 return redirect('/register') 121 elif password == '': 122 return redirect('/register') 123 elif mailaddress == '': 124 return redirect('/register') 125 elif User_mail.query.filter_by(mail=mailaddress).first(): 126 return redirect('/register') 127 else: 128 user = User(username=username, password=generate_password_hash(password, method='sha256'), mail=mailaddress, msg="なし", rep=4, star=0) 129 db.session.add(user) 130 db.session.commit() 131 user_mail = User_mail(username=username, mail=mailaddress) 132 db.session.add(user_mail) 133 db.session.commit() 134 print(mailaddress) 135 return redirect('/login') 136 else: 137 return render_template('register.html') 138 139@app.route('/login', methods=['GET', 'POST']) 140def login(): 141 if request.method == "POST": 142 143 username = request.form.get('name') 144 password = request.form.get('password') 145 # Userテーブルからusernameに一致するユーザを取得 146 user = User.query.filter_by(username=username).first() 147 if user: 148 if check_password_hash(user.password, password): 149 login_user(user) 150 print(current_user.username) 151 return redirect('/myhome') 152 else: 153 return redirect('/login') 154 else: 155 return redirect('/login') 156 else: 157 return render_template('login.html') 158 159 160 161@app.route('/myhome') 162@login_required 163def myhome(): 164 if VideoHit.query.filter_by(video_hit_mail=current_user.mail).first(): 165 for i in VideoHit.query.filter_by(video_hit_mail=current_user.mail).all(): 166 db.session.delete(i) 167 db.session.commit() 168 elif VideoHit.query.filter_by(video_star_mail=current_user.mail).first(): 169 for i in VideoHit.query.filter_by(video_star_mail=current_user.mail).all(): 170 db.session.delete(i) 171 db.session.commit() 172 current_user.video_query = 'off' 173 current_user.voting = 'off' 174 db.session.commit() 175 blogarticles = User.query.all() 176 votes = Vote.query.filter_by(vote_mail = current_user.mail).all() 177 voted_mails = [] 178 for i in votes: 179 voted_mails.append(i.voted_mail) 180 return render_template('myhome.html', voted_mails=voted_mails, current_user=current_user, username=current_user.username, blogarticles=blogarticles, math=math, int=int, str=str, os=os) 181

register.html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>ログイン</title> 8 <link rel="stylesheet" href="static/style.css"> 9 10</head> 11<body> 12 13 <form action="/register" method="post"> 14 <p class="text">ユーザーネーム</p> 15 <textarea class="area" name="name" id=""></textarea> 16 <p class="text">パスワード</p> 17 <textarea class="pass area" name="password" type="password" id="" ></textarea> 18 </br> 19<button>始める</button> 20 </form> 21</body> 22</html>

login.html

myhome.html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <link rel="stylesheet" href="static/style.css"> 8 <title>Document</title> 9</head> 10<body> 11 <p>ログイン成功</p> 12</body> 13</html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

このアプリがローカルで動作しているとのことですが、本当に動作していますか?

「動かない」と私が言っている理由は下の方に長々と書きましたが、とりあえずサーバ上で動作しない原因としては以下が考えられます。
確認してみてください。

  • sqliteのDBに日本語が入っていない。dbをローカルにDLしてくる等して、中を確認してみてください。
  • is_authenticatedが掲載コードに無いので、必ず認証失敗している可能性がある。Userクラスにここを参考にして、is_authenticatedを追加してみてください。

なお、今後も質問する場合は、質問には「動作するコード」の掲載をお願いします。

※掲載コードは動作しないので、「本当に動作していますか?」と書いています。
※動かない理由は以下。
まず、osがimportされていないため、以下は動作しません。

python

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

次に以下のdef index()でExceptionが発生します。
上の方にある[def index(): redirect('/register')]と関数名が重複しているためです。

python

1@app.route('/login') 2def index(): 3 if request.method == "POST":

[def index(): redirect('/register')]の関数名をhomeにリネームして実行したところ、以下のエラーで動作しません。
これはhome関数(昔のindex)がreturnしていないためです。

text

1Traceback (most recent call last): 2 File "venv\lib\site-packages\flask\app.py", line 2077, in wsgi_app 3 response = self.full_dispatch_request() 4 File "venv\lib\site-packages\flask\app.py", line 1526, in full_dispatch_request 5 return self.finalize_request(rv) 6 File "venv\lib\site-packages\flask\app.py", line 1545, in finalize_request 7 response = self.make_response(rv) 8 File "venv\lib\site-packages\flask\app.py", line 1701, in make_response 9 raise TypeError(

homeの最後をreturn redirect('/register')に変更して実行すると、以下のエラーで動作しません。
これはuser_loaderが定義されていないためです。

text

1Traceback (most recent call last): 2 File "venv\lib\site-packages\flask\app.py", line 2077, in wsgi_app 3 response = self.full_dispatch_request() 4 File "venv\lib\site-packages\flask\app.py", line 1525, in full_dispatch_request 5 rv = self.handle_user_exception(e) 6 File "venv\lib\site-packages\flask\app.py", line 1523, in full_dispatch_request 7 rv = self.dispatch_request() 8 File "venv\lib\site-packages\flask\app.py", line 1509, in dispatch_request 9 return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) 10 File "app.py", line 38, in register 11 return render_template('register.html') 12 File "venv\lib\site-packages\flask\templating.py", line 147, in render_template 13 ctx.app.update_template_context(context) 14 File "venv\lib\site-packages\flask\app.py", line 756, in update_template_context 15 context.update(func()) 16 File "venv\lib\site-packages\flask_login\utils.py", line 392, in _user_context_processor 17 return dict(current_user=_get_user()) 18 File "venv\lib\site-packages\flask_login\utils.py", line 359, in _get_user 19 current_app.login_manager._load_user() 20 File "venv\lib\site-packages\flask_login\login_manager.py", line 338, in _load_user 21 raise Exception( 22Exception: Missing user_loader or request_loader. Refer to http://flask-login.readthedocs.io/#how-it-works for more info. 23127.0.0.1 - - [18/Apr/2022 15:35:04] "GET /register HTTP/1.1" 500 - 24127.0.0.1 - - [18/Apr/2022 15:35:04] "GET /null HTTP/1.1" 404 - 25

user_loaderはflask-loginのサンプルを参考に、以下の通り追加して動かしてみます。

python

1@login_manager.user_loader 2def load_user(user_id): 3 return User.get(user_id)

上記追加後、localhost:5000にアクセスし、ユーザを追加します。
ユーザ名はaでパスワードbとして登録したところ、登録できました。(db.create_all()は事前に実行)

次に、localhost:5000/loginにアクセスし、上記ユーザでログインを試みます。
ログインできません。
これは、formがPOSTメソッドでアクセスしようとしているのに、@app.route('/login')def index()ではPOSTメソッドでのアクセスを許可していないためです。

POSTの許可が必要なので@app.route('/login', methods=['GET', 'POST'])に変更して実行すると、適当に追加したuser_loaderが正しくないせいでログインできません。
useridを取得できるようにする必要があるので、Class User に以下を追加します。

python

1 def get(self): 2 return self.id

上記を変更するとログインに成功したようです。

成功しましたが、待って下さい。
以下の部分で、login_requiredと書かれていないのでそもそもこのページは誰でも閲覧可能です。

python

1@app.route('/myhome')

そのため@app.route('/myhome')の下に@login_requiredを入れます。
これだとuseridが取得できないのでエラーになるため、user_loaderを以下のように変更します。

python

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

これでUnauthorizedが出ました。

flask-loginの公式ページによると、以下の4つを実装する必要があると書いてあります。

  • is_authenticated
  • is_active
  • is_anonymous
  • get_id()

python

1class User(UserMixin, db.Model): 2 id = db.Column(db.Integer, primary_key=True) 3 username = db.Column(db.String(50)) 4 password = db.Column(db.String(25)) 5 6 def get_id(self): 7 return self.id 8 9 def is_authenticated(self): 10 return True 11 12 def is_anonymous(self): 13 return False 14 15 def is_active(self): 16 return False

上記を追加するとログインに成功するようになりました。
念のため、以下を追加し、myhomeにアクセスしてみます。

python

1@app.route('/logout') 2@login_required 3def logout(): 4 logout_user() 5 return redirect('/myhome')

このURLを踏んだ後はUnauthorizedが表示されるようになったので問題無いでしょう。

次に、日本語のユーザID/パスワードで実施してみます。
IDをテスト、パスワードもテストとして登録し、ログインすると、問題無くログインできました。
確認環境がWindowsのため、なんとも言えませんが、ローカルで動いて、というのは再現できたような気がします。

投稿2022/04/18 07:23

FiroProchainezo

総合スコア2392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dabi

2022/04/19 15:47

コードが見にくかったのでコードを省略して書こうとしたのですが、そもそも動かないコードになってしまって申し訳ないです。ご指摘ありがとうございます。再度、 is_authenticated is_active is_anonymous get_id() を追加し、index.pyを編集しました。しかし、ローカルでは動くがレンタルサーバーにあげるとUnauthorizedエラーとなる問題が解決できません。解決策はありますか?
FiroProchainezo

2022/04/20 01:36

デバッグしてみてはいかがでしょうか? コアサーバー環境が無いため、実際にその動作を見ることができません。 いろいろな場所にprintを入れてみるなどの簡易デバッグは可能だと思います。
dabi

2022/04/20 12:12

質問の内容が変わってしまうようで申し訳ないですが、レンタルサーバーのデバックはどこからできるのでしょうか
FiroProchainezo

2022/04/21 02:01

管理ツールのどこかにログ表示みたいなのありませんか? XSERVERではあった気がします。 もしそれが無いなら、自分で適当にファイル出力するようにして、それをFTPとかでダウンロードして閲覧するか、SSHで接続してtailで眺めるなどすれば良いと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問