Create a change password page and update to database

Hi,

How to create a page to enable user to perform change password and able to update the new password back to database (pwd.csv // microsoft sql) ?

Only user that able to login have the authority to change his/her access’s password.

Hello @beginof,

To allow a user to change their password, all you need is a page with a form and several input boxes and a button.

Then on button push, the information goes to the dash server and then updates the SQL server from there.

Normally, to change a password, you have them type in the old password and then punch in the new password into two input boxes.

1 Like

Hi @jinnyzor,

Yes, it is exactly what I want.

Can you share some sample code?

Hi @beginof
Check out some sample login components here: DMC & DBC Building Blocks

3 Likes

Hi @beginof

Not sure if this will actually help as it will depend on how you built your app but this is what I have in my user management file for password change function:

def update_password(username, password, pw_change_date):
    hashed_password = generate_password_hash(password, method='sha256')
    upd = User_tbl.update().values(password=hashed_password, pw_change_date=pw_change_date).where(User_tbl.c.username == username)
    conn = engine.connect()
    conn.execute(upd)
    conn.close()

Then I call that function on a few different pages for password changing, password expiration page, admin page and user profile page when doing a manual password change.

I check the age of the user password and if over 180 days old it it returns the password expiration page and they are required to do their password change before proceeding.

I don’t check for current password when doing the password change (requested by the business as there’s lots of older users who will not remember their password for the dashboard as we have a 180 day session token so users are not required to log into the dashboard each time.) The dashboard runs on our own servers that require the users authentication to the Windows AD before being able to access the page. Thus also why the password requirements are only a length and age check.

On the user profile password change section I have a simple callback that takes the values entered into the input boxes and submits when user clicks button:

@app.callback(
   Output(component_id='profile-update-user', component_property='children'),
    Input(component_id='profile-pword-submit-button', component_property='n_clicks'),
    State(component_id='profile-pword-box', component_property='value'),
    State(component_id='profile-pword-box-confirm', component_property='value')
)
def update_user_password(n_clicks, new_pass, new_pass_confirm):
    if n_clicks is not None and current_user.is_authenticated:
        if len(new_pass) > 6:
            if new_pass == new_pass_confirm:
                return dmc.Alert(f'Password has been updated for {current_user.username} on {dl.current_time()}', title='SUCCESS', color='green', withCloseButton=True), um.update_password(current_user.username, new_pass, dl.current_time())
            else:
                return dmc.Alert('Passwords do not match, please try again.', title='FAILED', color='red', withCloseButton=True)
        else:
            return dmc.Alert('Password is too short, please try again.', title='FAILED', color='red', withCloseButton=True)

I return this as children to display to the user if password change succeeded or failed.

Similar thing on the admin page but I have a dropdown to select the user and when the password change is done through the admin page I set the password change date to 179 days ago (Which essentially makes it a temporary 1 day use password) instead of 180 days if the user changes it themselves.

@app.callback(
    Output(component_id='update-user', component_property='children'),
    Input(component_id='pword-submit-button', component_property='n_clicks'),
    State(component_id='dropdown-user-list', component_property='value'),
    State(component_id='pword-box', component_property='value'),
    State(component_id='pword-box-confirm',component_property='value')
    
)
def update_user_password(n_clicks, username, new_pass, new_pass_confirm):
    if n_clicks is not None:
        if new_pass == new_pass_confirm:
            expireAge = datetime.timedelta(days = 179)
            expireDate = pd.to_datetime(datetime.datetime.now() - expireAge).strftime('%Y-%m-%d %H:%M:%S')
            um.update_password(username, new_pass, expireDate)
            return dmc.Alert(f'Password has been updated for {username} on {datetime.datetime.now()}', title='SUCESS', color='green', style={'width': 500}, withCloseButton=True, 
                    icon=[DashIconify(
                    icon='mdi:success-circle-outline',
                    color=dmc.theme.DEFAULT_COLORS['green'][6])]
                    )
  
        else:
            return dmc.Alert('The passwords do not match, please try again', title='FAILED', color='red', style={'width': 500}, withCloseButton=True, 
                    icon=[DashIconify(
                    icon='mdi:alpha-x-circle-outline',
                    color=dmc.theme.DEFAULT_COLORS['red'][6])]
                    ),

Lastly here’s my expired password page callback. Note that this page it does require the user to enter their current password. Honestly this page mostly gets used after I do the Admin page password reset for the users, after the 24 hours once it expires because most of the time the users forget their password before it actually expires lol:

@app.callback(
    Output(component_id='profile-update-user-expired-password', component_property='children'),
    Input(component_id='expired-pword-submit-button', component_property='n_clicks'),
    Input(component_id='expired-uname-box', component_property='value'),
    State(component_id='expired-pword-box-new', component_property='value'),
    State(component_id='expired-pword-box-confirm', component_property='value'),
    State(component_id='expired-pword-box-old', component_property='value'),
    prevent_initial_call=True
)
def update_user_password_expired(n_clicks, username, new_pass, new_pass_confirm, old_password):
    if n_clicks is not None:
        user = User.query.filter_by(username=username).first()
        if len(new_pass) > 6:
            if new_pass == new_pass_confirm:
                if check_password_hash(user.password, old_password):
                    pw_change_date = dl.current_time()
                    return dmc.Alert(f'Password has been updated for {username} on {pw_change_date} you may proceed now', title='SUCCESS', color='green', withCloseButton=True), um.update_password(username, new_pass, pw_change_date)
                else:
                    return dmc.Alert('Username or current password was incorrect, please try again.', title='FAILED', color='red', withCloseButton=True)
            else:
                return dmc.Alert('New passwords do not match, please try again.', title='FAILED', color='red', withCloseButton=True)
        else:
            return dmc.Alert('New password is too short, please try again', title='FAILED', color='red', withCloseButton=True)

Good luck!

1 Like