Flash security login via username, not email

I wanted to have a field in the model User

through which the user registers as username

instead ofemail

I have defined:
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = 'username'

But I still get:

user_datastore.add_role_to_user(name, 'mgmt')
      File "/Users/boazin/sentinal/sentinel-cloud/.env/lib/python2.7/site-packages/flask_security/datastore.py", line 105, in add_role_to_user
        user, role = self._prepare_role_modify_args(user, role)
      File "/Users/boazin/sentinal/sentinel-cloud/.env/lib/python2.7/site-packages/flask_security/datastore.py", line 72, in _prepare_role_modify_args
        user = self.find_user(email=user)
      File "/Users/boazin/sentinal/sentinel-cloud/.env/lib/python2.7/site-packages/flask_security/datastore.py", line 203, in find_user
        return self.user_model.query.filter_by(**kwargs).first()
      File "/Users/boazin/sentinal/sentinel-cloud/.env/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1333, in filter_by
        for key, value in kwargs.items()]
      File "/Users/boazin/sentinal/sentinel-cloud/.env/lib/python2.7/site-packages/sqlalchemy/orm/base.py", line 383, in _entity_descriptor
        (description, key)
    InvalidRequestError: Entity '<class 'flask_app.models.User'>' has no property 'email'

      

The email seems to be hardcoded in flash security ...

Can I change it?

edit : User model (as mentioned in comment):

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True, index=True)
    password = db.Column(db.String(255))
    token = db.Column(db.String(255), unique=True, index=True)
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

      

+3


source to share


2 answers


From https://pythonhosted.org/Flask-Security/models.html

Fields are id, email, password, active

required. Add



email = db.Column(db.String(255), unique=True)

      

Just add your custom field username

.

+1


source


In enter username instead of email (using Flask-Security 1.7.0 or newer) you can replace field email

with field username

in User

model

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True, index=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

      

and update the config app

.

app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = 'username'

      

Then, so that users can log in using their username instead of email, we will use the fact that the LoginForm validation method assumes that the user has an identity attribute on the form field email

.

from flask_security.forms import LoginForm
from wtforms import StringField
from wtforms.validators import InputRequired

class ExtendedLoginForm(LoginForm):
    email = StringField('Username', [InputRequired()])

# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore,
                    login_form=ExtendedLoginForm)

      

This way we can log in using the username without overwriting the validation method or login pattern. Of course, this is a hack, and a more correct approach would be to add a custom method validate

that validates the form field username

to the class ExtendedLoginForm

and update the login template accordingly.



However, the above approach makes it easy to log in with a username or email address . To do this, define a user model with username and email fields.

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True)
    username = db.Column(db.String(255), unique=True, index=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

      

and update the config app

.

app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ('username','email')

      

Finally, create a custom login form.

from flask_security.forms import LoginForm
from wtforms import StringField
from wtforms.validators import InputRequired

class ExtendedLoginForm(LoginForm):
    email = StringField('Username or Email Address', [InputRequired()])

# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore,
                    login_form=ExtendedLoginForm)

      

Now, when logged in, Flask-Security will accept an email or username in the email form field.

+10


source







All Articles