I have difficulty in using the Flask-Login framework for authentication. I have looked through the documentation as thoroughly as possible but apparently I am missing something obvious.
class User():
def __init__(self, userid=None, username=None, password=None):
self.userid = userid
self.username = username
self.password = password
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.userid)
def __repr__(self):
return '<User %r>' % self.username
def find_by_username(username):
try:
data = app.mongo.db.users.find_one_or_404({'username': username})
user = User()
user.userid = data['_id']
user.username = data['username']
user.password = data['password']
return user
except HTTPException:
return None
def find_by_id(userid):
try:
data = app.mongo.db.users.find_one_or_404({'_id': userid})
user = User(data['_id'], data['username'], data['password'])
return user
except HTTPException:
return None
The above is my User class located in users/models.py
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
@login_manager.user_loader
def load_user(userid):
return find_by_id(userid)
The above is my user loader.
@mod.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
pw_hash = hashlib.md5(form.password.data).hexdigest()
user = find_by_username(form.username.data)
if user is not None:
if user.password == pw_hash:
if login_user(user):
flash('Logged in successfully.')
return redirect(request.args.get('next') or url_for('users.test'))
else:
flash('Error')
else:
flash('Username or password incorrect')
else:
flash('Username or password incorrect')
return render_template('users/login.html', form=form)
There is no apparently error message, but when trying to access any views decorated with @login_required
, it redirects me to the login form. Best as I can tell, the login_user
function isn't actually working although it returns True
when I called it. Any advice appreciated.
After stepping through a debugger for a while, I finally fixed the problem.
The key issue is that I was attempting to use the _id
parameter from the MongoDB collection as the userid. I did not realize that the _id
parameter was an ObjectID
type instead of a string or unicode which I needed.
def find_by_username(username):
try:
data = app.mongo.db.users.find_one_or_404({'username': username})
user = User(unicode(data['_id']), data['username'], data['password'])
return user
except HTTPException:
return None
def find_by_id(userid):
try:
data = app.mongo.db.users.find_one_or_404({'_id': ObjectId(userid)})
user = User(unicode(data['_id']), data['username'], data['password'])
return user
Modifying the two functions appropriately fixed this error.
If you've verified it's not your login_user
function, then that leaves your find_by_id
function.
The source code for the user_loader
says:
The function you set should take a user ID (a
unicode
) and return a user object, orNone
if the user does not exist.
Your find_by_id
function uses find_one_or_404
which raises an eyebrow. I'd add some extra debugging around that function, add some prints, or logging to show it's being called, with the correct unicode id, and that it's returning a User
object, or None
.
Hopefully that'll get you closer to narrowing down the problem.
I can't seem to find the place where you assign the user_id to the session after validating the form:
session['user_id'] = form.user.id
Have a look at this SimpleRegistrationForm on Github as an example
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.