Lucas Infante
Lucas Infante

Reputation: 798

Error when confirming registration using flask-security

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.

EDIT

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?

Original

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

Answers (2)

shmancelot
shmancelot

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

deadbeef404
deadbeef404

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

Related Questions