flask-security login via username and not email
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.