flask-security login via username and not email

泪湿孤枕 提交于 2020-06-10 21:12:31

问题


I wanted to have the field in User model that through it the user logs in as username instead of email

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

But I'm still getting:

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'

It seems that email is hardcoded into flask-security...

Can I change it?

edit: The User Model (as requested in the 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'))

回答1:


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

Fields id, email, password, active is essential.So add

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

Just add your custom username field along this.




回答2:


To login with a username instead of an email address (using Flask-Security 1.7.0 or higher), you can replace the email field with a username field in the 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 app configuration.

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

Next, to allow users to login using a username instead of an email, we will use the fact that the LoginForm validation method assumes the user identity attribute is in the email form field.

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 login using a username without rewriting the validation method or the login template. Of course, this is a hack and the more correct approach would be to add a custom validate method, which checks a username form field, to the ExtendedLoginForm class and to update the login template accordingly.

However, the approach above makes it easy to login with a username or an email address. To do this, define a user model with both a username and email field.

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 app configuration.

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

Finally, create the 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 logging in, Flask-Security will accept an email or username in the email form field.



来源:https://stackoverflow.com/questions/30827696/flask-security-login-via-username-and-not-email

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!