Reputation: 798
I'm using flask-security to handle user registration, login, etc. I'm facing a problem when registering a new user using the default flask-security views.
I managed to advance a little on solving the problem. The initial problem was that I wasn't providing a load_user callback. Now I'm doing it:
@login_manager.user_loader
def load_user(user_id):
return User.objects.get(id=user_id)
Problem is that the confirmation url/view seems to use an AnonymousUser and so, the query filter does not match the correct user. Any clues guys?
I'm able to provide user mail and password in the registration view, I successfully receive a confirmation e-mail (the default template provided by flask-security) but when I try to confirm the account clicking on the mail confirmation link I get the following attribute error:
AttributeError: 'AnonymousUserMixin' object has no attribute 'roles'
Here is the full traceback:
Traceback (most recent call last):
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site- packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/views.py", line 226, in confirm_email
logout_user()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/utils.py", line 92, in logout_user
identity=AnonymousIdentity())
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/blinker/base.py", line 267, in send
for receiver in self.receivers_for(sender)]
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 469, in _on_identity_changed
self.set_identity(identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 418, in set_identity
self._set_thread_identity(identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 463, in _set_thread_identity
identity=identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/blinker/base.py", line 267, in send
for receiver in self.receivers_for(sender)]
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/core.py", line 217, in _on_identity_loaded
for role in current_user.roles:
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'AnonymousUserMixin' object has no attribute 'roles'
Here is my app configuration:
from flask import Flask
from flask.ext.security import MongoEngineUserDatastore, Security
from flask_login import LoginManager
from flask_mail import Mail
from wpapp.models import db, User, Role
from wpapp.views import frontend
from wpapp.configs import CONFS
login_manager = LoginManager()
app = Flask(__name__)
app.config["MONGODB_SETTINGS"] = CONFS['MONGODB_SETTINGS']
app.config["SECRET_KEY"] = CONFS['SECRET_KEY']
app.config['SECURITY_PASSWORD_HASH'] = CONFS['SECURITY_PASSWORD_HASH']
app.config['SECURITY_PASSWORD_SALT'] = CONFS['SECURITY_PASSWORD_SALT']
app.config['SECURITY_REGISTERABLE'] = CONFS['SECURITY_REGISTERABLE']
app.config['SECURITY_CONFIRMABLE'] = CONFS['SECURITY_CONFIRMABLE']
app.config['SECURITY_RECOVERABLE'] = CONFS['SECURITY_RECOVERABLE']
app.config['SECURITY_REGISTER_URL'] = CONFS['SECURITY_REGISTER_URL']
app.config['MAIL_SERVER'] = CONFS['MAIL_SERVER']
app.config['MAIL_PORT'] = CONFS['MAIL_PORT']
app.config['MAIL_USE_SSL'] = CONFS['MAIL_USE_SSL']
app.config['MAIL_USERNAME'] = CONFS['MAIL_USERNAME']
app.config['MAIL_PASSWORD'] = CONFS['MAIL_PASSWORD']
mail = Mail(app)
app.register_blueprint(frontend)
db.init_app(app)
user_datastore = MongoEngineUserDatastore(db, User, Role)
security = Security(app, user_datastore)
login_manager.init_app(app)
if __name__ == '__main__':
app.run()
And here are my models definitions (I'm using mongodb):
from flask.ext.mongoengine import MongoEngine
from flask.ext.security import UserMixin, RoleMixin
db = MongoEngine()
class Role(db.Document, RoleMixin):
name = db.StringField(verbose_name=u"Nome",
help_text=u"Inserir um nome para identificação do Papel.",
max_length=50,
required=True,
unique=True)
description = db.StringField(verbose_name=u"Descrição",
help_text=u"Inserir descrição sucinta sobre o Papel.",
max_length=255)
class User(db.Document, UserMixin):
email = db.StringField(verbose_name=u"E-mail",
help_text=u"Cadastrar um e-mail válido.",
max_length=255,
required=True,
unique=True)
password = db.StringField(verbose_name=u"Senha",
help_text=u"Cadastrar sua senha para acesso.",
required=True,
max_length=255)
active = db.BooleanField(verbose_name=u"Ativo",
help_text=u"Indica se o usuário está ativo no sistema.",
default=True)
confirmed_at = db.DateTimeField(verbose_name=u"Confirmação",
help_text=u"Horário de confirmação do usuário")
roles = db.ListField(db.ReferenceField(Role),
verbose_name=u"Papéis",
help_text=u"Atribuir papéis ao usuário.",
default=[])
Does anyone have a clue on what may the problem be? Thanks in advance!
Upvotes: 1
Views: 1239
Reputation: 21
Thanks deadbeef404, pretty much nailed it. I would have commented on your answer, but I don't have any rep.
Actually flask login uses it's own AnonymousUserMixin class. The following snippet shows how to override it with flask security's AnonymousUser class.
login_manager = LoginManager()
from flask.ext.security import AnonymousUser
login_manager.anonymous_user = AnonymousUser
Upvotes: 2
Reputation: 623
I'm not sure what your exact problem is but it seems that flask principal is trying to use the AnonymousUser
(the identity in memory when no one is logged in) like an authenticated user. An AnonymousUser
doesn't have a roles
attribute so when it tries to access it, it throws an Exception.
Upvotes: 0