mysqlauthenticationflaskregistrationflask-security

user_datastore.create_user() not adding user to MySQL db


I'm trying to create an authentication system using Python Flask. However, Whenever I submit my registration form, there are no errors and it redirects correctly, but the user information isn't ever stored in my MySQL database.

Here's the code I'm using to setup the user_datastore:

(app initiation and other config)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:dumbypassword@localhost/myDB

db = SQLAlchemy(app)

roles_users = db.Table('roles_users',
                       db.Column('email', db.String(50), db.ForeignKey('users.email')),
                       db.Column('role', db.String(20), db.ForeignKey('roles.role'))
              )


class User(db.Model):
    __tablename__ = 'users'
    firstName = db.Column(db.String(20), nullable=False)
    lastName = db.Column(db.String(30), nullable=False)
    email = db.Column(db.String(50), primary_key=True, unique=True, nullable=False)
    password = db.Column(db.LargeBinary())  # should be hashed with salt
    salt = db.Column(db.String(22))
    active = db.Column(db.Boolean())
    confirmed = db.Column(db.DateTime())
    roles = db.relationship(
        'Role',
        secondary=roles_users,
        backref=db.backref('users')
    )


class Role(db.Model):
    __tablename__ = 'roles'
    role = db.Column(db.String(20), primary_key=True, nullable=False)
    description = db.Column(db.String(255))


user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)

And here's the logic in my register page for creating a new user:

salt = bcrypt.gensalt()
user_datastore.create_user(
    firstName=request.form.get('firstName'),
    lastName=request.form.get('lastName'),
    email=request.form.get('email'),
    password=bcrypt.hashpw(request.form.get('password').encode('utf-8'), salt),  # TODO: Need to bcrypt pass + salt
    salt=salt,
    active=1,
    confirmed=datetime.now()
)

After submitting the registration form with method "POST," none of the information is stored :( See my query and result: enter image description here

I have a sneaking suspicion that I'm butchering all of this, so any help, including but not limited to naming/formatting conventions, would be appreciated.


Solution

  • To answer your precise question - looks like you aren't committing the transaction to the DB. Flask-Security does this as part of a @after_this_request so that if any errors occur during the request, the data is rolled back. So - somewhere after processing you need to call datastore.commit()

    A meta issue is - looks like you are re-inventing a bunch of stuff. Flask-Security-Too already manages registration, and you can easily extend that - furthermore it is best practice to let security oriented packages do their job - so for passwords and salting - Flask-Security and passlib already have a lot of history managing those - so unless you have some specific requirements (and I'd like to hear about those) leave that to them. Definitely don't store the salt in the DB along with the user record. Flask-Security-Too has a public api 'hash_password' you can use (it uses passlib's CryptoContext to pass appropriate options).