我正在尝试尝试建立登录方法一段时间。我正在运行Flask应用,并且运行良好。所有这些都在我的机器上本地运行。当前,我正在使用pymongo
和MongoClient
来建立与数据库的连接。一切都很好,如果可能的话,我想不要更改它。
我正在尝试使用Flask-Login
通过users
创建一个usermixin
类。这是我严重失败的地方。我尝试了几种不同的方法,但我的问题是如何从数据库中提取数据。我之前已经使用SQL DB做到了这一点,但是对于这个项目,我明确希望使用MongoDB。这是我试图遵循的教程,但是我很难理解所有内容,因为没有很好地解释每一行的内容。
这是我与数据库的连接:
client = MongoClient('mongodb://localhost:27017')
,这是我当前没有的课程,需要帮助的地方。
class User(UserMixin):
def __init__(self, username, password_hash):
self.username = username
self.password_hash = password_hash
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def get_id(self):
return self.username
@login_manager.user_loader
def load_user(user_id):
return User.objects(pk=user_id).first()
然后我的最后一部分是我的登录表单:
@app.route('/login', methods=["GET" , "POST"])
def login():
if request.method == "GET":
return render_template("login.html", error=False)
if request.method == "POST":
check_user = request.form["username"]
if check_user:
if check_password_hash(check_user['password'], request.form["password"]):
login_user(check_user)
return redirect(url_for('index'))
我知道本教程使用的MongoEngine
尚未使用,但对于如何使上面的代码正常工作或如何适应它会有所帮助。当我运行这段代码时,我没有得到任何错误,只是没有用。我的测试是我尝试登录,然后尝试转到退出页面,该页面装有以下代码:
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
当我这样做时,它不会加载页面,并且我会收到未授权页面的通知。因此,我知道我的代码无法正常工作。最后,我将所有模板都放在一个静态文件位置。
预先感谢您的帮助,如果有任何不清楚的地方,请询问,我将尝试添加更多详细信息。具体程度越高,我将越能提供帮助。
更新:
我意识到,描述数据库的结构以确保我能够正确访问它可能也很重要,因为那是我遇到问题的重点。我有一个数据库,该数据库的集合名为 Users (用户),该数据库的结构是每个文档都是不同的用户记录,例如:
{
"_id" : 1,
"Reset" : false,
"FirstName" : "John",
"LastName" : "Doe",
"Email" : "JohnDoe@gmail.com",
"Username" : "",
"admin" : false,
"Pass" : "[hashed_password]"
}
{
"_id" : 2,
"Reset" : true,
"FirstName" : "Jane",
"LastName" : "Smith",
"Email" : "JaneSmith@hotmail.com",
"Username" : "Jane",
"admin" : false,
"Pass" : "[hashed_password]"
}
{
"_id" : 3,
"Reset" : true,
"FirstName" : "Gary",
"LastName" : "Bettman",
"Email" : "GBettman@yahoo.com",
"Username" : "HockeyGuy",
"admin" : false,
"Pass" : "[hashed_password]"
}
答案 0 :(得分:0)
您需要了解的有关Flask登录的信息:此扩展与应用程序的用户模型一起使用,并期望在其中实现某些属性和方法。 (来源:https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins)。
以下列出了四个必填项:
is_authenticated
:如果用户具有有效的凭据,则该属性为True,否则为False。
is_active
:如果用户帐户处于活动状态,则该属性为True;否则为False。
is_anonymous
:对于常规用户,该属性为False,对于特殊的匿名用户,该属性为True。
get_id()
:一种以字符串形式返回用户唯一标识符的方法
不幸的是,官方文档和 Miguel Grinberg的优秀博客中的所有示例均使用SQLAlchemy。好消息,可以用Pymongo实施它...
解决方案
routes.py
from flask import Flask
from flask_pymongo import PyMongo
from flask_login import LoginManager
from flask import render_template, url_for, request, flash
from app.forms import Login
from flask import request
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import current_user, login_user, logout_user, login_required
mongo = PyMongo(app)
login = LoginManager(app)
login.login_view = 'login'
class User:
def __init__(self, username):
self.username = username
@staticmethod
def is_authenticated():
return True
@staticmethod
def is_active():
return True
@staticmethod
def is_anonymous():
return False
def get_id(self):
return self.username
@staticmethod
def check_password(password_hash, password):
return check_password_hash(password_hash, password)
@login.user_loader
def load_user(username):
u = mongo.db.Users.find_one({"Name": username})
if not u:
return None
return User(username=u['Name'])
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = Login()
if form.validate_on_submit():
user = mongo.db.Users.find_one({"Name": form.name.data})
if user and User.check_password(user['Password'], form.password.data):
user_obj = User(username=user['Name'])
login_user(user_obj)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('index')
return redirect(next_page)
else:
flash("Invalid username or password")
return render_template('login.html', title='Sign In', form=form)
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
form.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from wtforms.validators import DataRequired
class Login(FlaskForm):
name = StringField('name' validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
login = SubmitField('Login')
假设在Mongodb的一侧有一个包含一些登录信息的集合(用户)。例如:
{
Name: [username],
Password: [hashed_password]
}
有关各行代码的功能的进一步说明,建议您参考以下链接:
答案 1 :(得分:0)
我发现flask-login
,UserMixin
,pymongo
的以下作品
这是用户模型
import datetime
import uuid
from depo import bcrypt, login_manager
from flask import session, flash
from depo.common.database import Database
from depo.models.blog import Blog
from flask_login import UserMixin
class User(UserMixin):
def __init__(self, username, email, password, _id=None):
self.username = username
self.email = email
self.password = password
self._id = uuid.uuid4().hex if _id is None else _id
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return self._id
@classmethod
def get_by_username(cls, username):
data = Database.find_one("users", {"username": username})
if data is not None:
return cls(**data)
@classmethod
def get_by_email(cls, email):
data = Database.find_one("users", {"email": email})
if data is not None:
return cls(**data)
@classmethod
def get_by_id(cls, _id):
data = Database.find_one("users", {"_id": _id})
if data is not None:
return cls(**data)
@staticmethod
def login_valid(email, password):
verify_user = User.get_by_email(email)
if verify_user is not None:
return bcrypt.check_password_hash(verify_user.password, password)
return False
@classmethod
def register(cls, username, email, password):
user = cls.get_by_email(email)
if user is None:
new_user = cls( username, email, password)
new_user.save_to_mongo()
session['email'] = email
return True
else:
return False
def json(self):
return {
"username": self.username,
"email": self.email,
"_id": self._id,
"password": self.password
}
def save_to_mongo(self):
Database.insert("users", self.json())
这是路线
from flask import flash, render_template, request, session, make_response, redirect, url_for
from depo import app, bcrypt, login_manager
from depo.models.blog import Blog
from depo.models.post import Post
from depo.models.user import User
from depo.common.database import Database
from depo.usercon.forms import RegistrationForm, LoginForm
from flask_login import login_user
@app.before_first_request
def initialize_database():
Database.initialize()
@app.route("/register", methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
if request.method == 'POST':
username = request.form["username"]
email = request.form["email"]
password = bcrypt.generate_password_hash(request.form["password"])
.decode('utf-8')
find_user = User.get_by_email(email)
if find_user is None:
User.register(username, email, password)
flash(f'Account created for {form.username.data}!', 'success')
return redirect(url_for('home'))
else:
flash(f'Account already exists for {form.username.data}!', 'success')
return render_template('register.html', title='Register', form=form)
@app.route("/login", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
email = request.form["email"]
password = request.form["password"]
find_user = Database.find_one("users", {"email": email})
if User.login_valid(email, password):
loguser = User(find_user["_id"], find_user["email"], find_user["password"])
login_user(loguser, remember=form.remember.data)
flash('You have been logged in!', 'success')
return redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return render_template('login.html', title='Login', form=form)
@login_manager.user_loader
def load_user(user_id):
user =User.get_by_id(user_id)
if user is not None:
return User(user["_id"])
else:
return None
app
可能还需要一些代码,如果尚未初始化的话
from flask_login import LoginManager
login_manager = LoginManager(app)
答案 2 :(得分:0)
我在此之后遇到了同样的问题,https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins。
为了让它在 Mongo 中运行,我做了一些更改,但我确实从 MongoClient 切换到了 MongoEngine。
__init__.py
from flask import Flask
from config import Config
from flask_mongoengine import MongoEngine, Document
from flask_login import LoginManager
app = Flask(__name__)
app.config.from_object(Config)
login = LoginManager(app)
login.login_view = 'login'
db = MongoEngine(app)
from app import routes
from app.model import user
.
app/model/user.py
from datetime import datetime
from app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
@login.user_loader
def load_user(id):
return User.objects.get(id=id)
class User(UserMixin, db.Document):
meta = {'collection': 'users'}
username = db.StringField(default=True)
email = db.EmailField(unique=True)
password_hash = db.StringField(default=True)
active = db.BooleanField(default=True)
isAdmin = db.BooleanField(default=False)
timestamp = db.DateTimeField(default=datetime.now())
def __repr__(self):
return '<User {}>'.format(self.username)
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)
.
app/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from app.model.user import User
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me')
submit = SubmitField('Sign In')
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password2 = PasswordField(
'Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
def validate_username(self, username):
user = User.objects(username=username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
def validate_email(self, email):
user = User.objects(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
.
app/routes.py
from flask import render_template, flash, redirect, request, url_for
from app import app, db
from app.forms import LoginForm, RegistrationForm
from flask_login import current_user, login_user, login_required, logout_user
from app.model.user import User
@app.route('/')
@app.route('/index')
@login_required
def index():
posts = [
{
'author': {'username': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'username': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html", title='Home Page', posts=posts)
@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():
user = User.objects(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('index')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
user.save()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)