How to Create a Login Form with Postgres and Python - Part 4: Show Form to Set New Password
Introduction
In this tutorial, we will build a registration system that allows users of your Postgres- and Python-based web application to create a username and password, add a new user to the database, send a confirmation email, handle the confirmation email click, and set a confirmed flag in the database. This article is part four of a five-part series. In this series, we will address the following:
- Part 1: Build the sign-in form using HTML, CSS, and Javascript. Interaction with the database will be absent from this part 1.
- Part 2: Validate user input of email and password, create a hash of the user’s password, and compare it to the hash we have in our PostgreSQL database. We’ll use Python for this part of the tutorial. If they verify, we send them on to the rest of your application.
- Part 3: Email the user a link because they clicked “I forgot my password.”
- Part 4: Serve the user a modified Javascript/HTML/CSS login form to create a new password.
- Part 5: Validate, put hash of their new password into the database, and send user to a page with a message.
Overview of this article
In this part 4, we will modify the HTML login form we created in part one so that it can serve more than one purpose. It will actually now have two HTML forms, one for signing in and one for resetting the password.
Assumptions and prerequisites
We’ll assume you have followed the instructions in parts 1, 2, and 3, starting here: here.
The code
Study the code below, paste it into your favorite editor, save the file as “sign/_in.html“, upload to your server’s “/template” folder, and try it out!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | <html> <head> <link rel="shortcut icon" href="favicon.ico" /> <title>Login</title> <meta name="description" content="Sign in here to play the greatest game ever seen!" /> <!-- In the interest of modularity, once you get this working, --> <!-- we recommend you create a stylesheet file and refer to it --> <!-- from here using the line below --> <!--link href="/css/non-existent-file.css" rel="stylesheet" type="text/css"--> <!-- --> <script language="JavaScript" type="text/javascript"> <!-- /* checkform() is the overall function called from */ /* our HTML when the user submits the form */ function checkform (form) { /* isEmpty() returns true and alerts the user if they left a field empty */ function isEmpty (fixwhat, s_called) { if (fixwhat=="") { alert("Please enter " + s_called); return true; } else { return false; } } /* charCheck() returns false and alerts the user if they used any non-alphanumeric characters */ function charCheck(fixwhat) { var validchars = '@-_.0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; if(isValid(fixwhat,validchars)) { return true; } else { alert("Please use only letters or numbers in this field"); return false; } } /* isValid is used by the charCheck() function to look through each 'validchars' one at a time */ function isValid(string,validchars) { for (var i=0; i< string.length; i++) { if (validchars.indexOf(string.charAt(i)) === -1) {return false;} } return true; } // Check for empty fields if (is_empty (form.t_email.value,"your email address")) { form.t_email.focus(); return false;} // IMPORTANT: The "if" below that looks for "frmSignIn" is new code // We only need password if they are signing in, NOT if they want a password reset email if (form.id.value === "frmSignIn") { if (is_empty (form.t_password.value,"your password")) { form.t_password.focus(); return false;} } //check for weird chars if (charCheck(form.t_email.value)===false) {form.t_email.focus(); return false;} // IMPORTANT: The "if" below that looks for "frmSignIn" is new code if (form.id.value === "frmSignIn") { if (charCheck(form.t_password.value)===false) {form.t_password.focus(); return false;} } return true ; } //--> </script> <!-- Some basic styles to set element colors, size, and align our form fields --> <!-- As mentioned above, we recommend you place the following CSS into a file --> <!-- So that every page of your site can refer to that one CSS file, which --> <!-- increases ease of modification in the future. --> <style type="text/css"> html, body { padding: 1; margin: 1; } input { font-size: 16px; font-family: Helvetica, sans-serif; } body { background-color: #66aacc; font-family: sans-serif, arial, helvetica; padding-bottom: 50px; } .container { background-color: #ffffff; max-width: 600px; margin: 20px auto 0 auto; padding: 15px 20px 1px 20px; } .form-row { padding: 10px 0; display: flex; } .form-row label { padding-right: 10px; } .form-row input { padding-right: 10px; flex: 1; } </style> </head> <body> <!-- Note: later you may wish to add an include pointer (include) to a common header file here --> <!-- or above this mark, depending on other factors. --> <!-- Why a common header file? This is so that all pages share the same footer. --> <!-- Changing the one header file will change the header of every page on your site. --> <!-- For example, you may wish to put your logo and navigation links in this file --> <!-- or even have a separate file for header and separate file for navigation. --> <!-- The message you see below is why we call this a template --> <!-- message is filled in by the Python file as it calls up this HTML --> <!-- Later you may wish to separate page title from message --> <h1>{{message}}</h1> <!-- Note: this 'container' class refers to the '.container' we see in the CSS we wrote above --> <div class="container"> <!-- Set up form type and the file to process user input --> <!-- Notice how the onsubmit parameter calls our checkform javascript function --> <!-- This checks to make sure the user: --> <!-- (a) didn't leave any field empty; and --> <!-- (b) used only valid alphanumeric characters --> <form id="frmSignIn" name="frmSignIn" action="/sign_in?stage=login" method="post" onsubmit="return checkform(this);" > <!-- text box for user to enter their Email address --> <!-- Notice our input has an id of 't_email'. --> <!-- This is used by our checkform javascript function. --> <div class="form-row"> <label for="Email">Email address:</label> <input type="text" id="t_email" name="t_email" /> </div> <!-- text box for user to create a Password --> <!-- Notice our input has an id of 't_password'. --> <!-- This is used by our checkform javascript function. --> <div class="form-row"> <label for="Email">Password:</label> <input type="text" id="t_password" name="t_password" /> </div> <!-- button for user to submit the form --> <div class="form-row"> <input type="submit" id="btn_submit_sign_in" value="Sign In" /> </div> <!-- Close our form --> </form> <!-- ------------------- --> <!-- Password reset form --> <!-- ------------------- --> <h2>I forgot my password</h2> <form id="frmResetPassword" name="frmResetPassword" action='/sign_in?stage=forgot&ID_user={{request.args.get("ID_user")}}' method="post" onsubmit="return checkform(this);" > <div class="form-row"> <label for="Email">Email address:</label> <input type="text" id="t_email" name="t_email" /> </div> <div class="form-row"> <input type="submit" id="btn_submit_reset" value="Send me a password reset link" /> </div> </form> <!-- Close our container div --> </div> <!-- Note: later you may wish to add an include pointer (include) to a footer file here. --> <!-- This is so that all pages share the same footer. Changing the one footer file will change --> <!-- the footer of every page on your site. --> <!-- Close the body of our HTML document --> </body> </html> |
Conclusion
You’ve now completed part 4 of 5 of creating a registration feature for a web application. In part five we will write more Python to validate and process the new password.
Pilot the ObjectRocket Platform Free!
Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.
Get Started