title
Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication

description
In this Python Flask Tutorial, we will be learning how to add users to our database. We will then create an authentication system so that users can log in and log out of our application. We will be using the flask-bcrypt and flask-login extensions to help us with this. Let's get started... The code for this series can be found at: https://github.com/CoreyMSchafer/code_snippets/tree/master/Python/Flask_Blog ✅ Support My Channel Through Patreon: https://www.patreon.com/coreyms ✅ Become a Channel Member: https://www.youtube.com/channel/UCCezIgC97PvUuR4_gbFUs5g/join ✅ One-Time Contribution Through PayPal: https://goo.gl/649HFY ✅ Cryptocurrency Donations: Bitcoin Wallet - 3MPH8oY2EAgbLVy7RBMinwcBntggi7qeG3 Ethereum Wallet - 0x151649418616068fB46C3598083817101d3bCD33 Litecoin Wallet - MPvEBY5fxGkmPQgocfJbxP6EmTo5UUXMot ✅ Corey's Public Amazon Wishlist http://a.co/inIyro1 ✅ Equipment I Use and Books I Recommend: https://www.amazon.com/shop/coreyschafer ▶️ You Can Find Me On: My Website - http://coreyms.com/ My Second Channel - https://www.youtube.com/c/coreymschafer Facebook - https://www.facebook.com/CoreyMSchafer Twitter - https://twitter.com/CoreyMSchafer Instagram - https://www.instagram.com/coreymschafer/ #Python #Flask

detail
{'title': 'Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication', 'heatmap': [{'end': 971.845, 'start': 932.836, 'weight': 0.761}, {'end': 1219.33, 'start': 1189.911, 'weight': 0.78}, {'end': 1275.949, 'start': 1246.323, 'weight': 0.711}, {'end': 1454.626, 'start': 1413.593, 'weight': 0.725}, {'end': 1622.92, 'start': 1582.967, 'weight': 1}, {'end': 1876.966, 'start': 1834.978, 'weight': 0.769}, {'end': 2270.304, 'start': 2238.076, 'weight': 0.753}, {'end': 2410.577, 'start': 2353.622, 'weight': 0.778}], 'summary': 'Tutorial series on python flask covers database user management, flask bcrypt password hashing, debugging, custom validation, flask login system, session management, database login logic, user authentication, user redirection, and authorization system implementation.', 'chapters': [{'end': 80.061, 'segs': [{'end': 57.144, 'src': 'embed', 'start': 0.229, 'weight': 0, 'content': [{'end': 1.25, 'text': "Hey there, how's it going everybody?", 'start': 0.229, 'duration': 1.021}, {'end': 9.074, 'text': "In this video, we'll be learning how to use our application to add users to our database and also how to authenticate users so that they can log in,", 'start': 1.57, 'duration': 7.504}, {'end': 12.396, 'text': 'log out and also soon be able to create posts and things like that.', 'start': 9.074, 'duration': 3.322}, {'end': 13.977, 'text': "So let's go ahead and get started.", 'start': 12.756, 'duration': 1.221}, {'end': 20.26, 'text': 'So in a previous video, we created our database and saw how we could manually create some users and posts.', 'start': 14.437, 'duration': 5.823}, {'end': 23.242, 'text': "But now let's add that same logic to our application.", 'start': 20.6, 'duration': 2.642}, {'end': 26.024, 'text': 'to create these users through the registration form.', 'start': 23.602, 'duration': 2.422}, {'end': 30.927, 'text': "Now, before we create our users, we're going to need a way to hash our passwords.", 'start': 26.404, 'duration': 4.523}, {'end': 38.432, 'text': 'So, in the previous video, we were using plain text passwords for our examples, but you never want to do this with your actual website,', 'start': 31.567, 'duration': 6.865}, {'end': 44.936, 'text': 'because if anyone was to ever get access to your database, then they would have the logins for all of your users,', 'start': 38.432, 'duration': 6.504}, {'end': 46.297, 'text': "and that's definitely not a good thing.", 'start': 44.936, 'duration': 1.361}, {'end': 52.021, 'text': 'So there are several different hashing algorithms, but one good one that we can use is called bcrypt.', 'start': 47.058, 'duration': 4.963}, {'end': 57.144, 'text': "and there's an extension for Flask that makes this easy to use and that is called Flask bcrypt.", 'start': 52.341, 'duration': 4.803}], 'summary': 'Tutorial on adding users to a database, authenticating users, and hashing passwords using flask bcrypt.', 'duration': 56.915, 'max_score': 0.229, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0229.jpg'}], 'start': 0.229, 'title': 'Database user management with flask', 'summary': 'Covers the process of adding users to the database, authenticating users for logging in and out, and the importance of hashing passwords using bcrypt for security, along with the installation of flask bcrypt using pip.', 'chapters': [{'end': 80.061, 'start': 0.229, 'title': 'Database user management with flask', 'summary': 'Covers adding users to the database, authenticating users for logging in and out, and the importance of hashing passwords using bcrypt for security, along with the installation of flask bcrypt using pip.', 'duration': 79.832, 'highlights': ['The chapter emphasizes the significance of using bcrypt to hash passwords for security, as plain text passwords can compromise user logins if the database is compromised.', 'The video focuses on the process of adding users to the database, along with the upcoming ability to create posts using the application.', 'The importance of using Flask bcrypt for easy password hashing is highlighted, with a demonstration of its installation using pip in the project directory.', 'The necessity of securely authenticating users for logging in and out is addressed for maintaining application security and user privacy.', 'The previous usage of plain text passwords in the examples is highlighted as a practice to avoid in actual web applications for safeguarding user data.']}], 'duration': 79.832, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0229.jpg', 'highlights': ['The chapter emphasizes the significance of using bcrypt to hash passwords for security, as plain text passwords can compromise user logins if the database is compromised.', 'The necessity of securely authenticating users for logging in and out is addressed for maintaining application security and user privacy.', 'The importance of using Flask bcrypt for easy password hashing is highlighted, with a demonstration of its installation using pip in the project directory.', 'The video focuses on the process of adding users to the database, along with the upcoming ability to create posts using the application.', 'The previous usage of plain text passwords in the examples is highlighted as a practice to avoid in actual web applications for safeguarding user data.']}, {'end': 687.878, 'segs': [{'end': 180.447, 'src': 'embed', 'start': 153.038, 'weight': 2, 'content': [{'end': 159.54, 'text': "So this means that if someone was to steal this from your database, then they wouldn't even be able to use a hash table to crack these passwords.", 'start': 153.038, 'duration': 6.502}, {'end': 166.282, 'text': "So if it's a different hash every time, then how can we verify if the user enters the correct password?", 'start': 160.22, 'duration': 6.062}, {'end': 173.504, 'text': 'If we just hash their entered password and compare it to what we have stored in the database, then those will most likely be different.', 'start': 166.642, 'duration': 6.862}, {'end': 175.545, 'text': 'So we need to use another method.', 'start': 173.844, 'duration': 1.701}, {'end': 180.447, 'text': 'called check password hash in order to check if those passwords are equal.', 'start': 175.945, 'duration': 4.502}], 'summary': 'Using a different hash for each password makes it difficult for hackers to crack passwords; a method called check password hash is used for verification.', 'duration': 27.409, 'max_score': 153.038, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0153038.jpg'}, {'end': 278.19, 'src': 'embed', 'start': 251.496, 'weight': 0, 'content': [{'end': 254.899, 'text': "And now to initialize this, it's going to be pretty similar to SQL alchemy here.", 'start': 251.496, 'duration': 3.403}, {'end': 257.841, 'text': "So we'll just say from flask bcrypt.", 'start': 255.219, 'duration': 2.622}, {'end': 273.188, 'text': 'import that bcrypt class and then down here at the bottom we will say bcrypt is equal to bcrypt and we want to pass in that app to that bcrypt class to initialize that.', 'start': 258.361, 'duration': 14.827}, {'end': 278.19, 'text': "Okay so now let's open up our routes and see what our current registration logic is.", 'start': 273.568, 'duration': 4.622}], 'summary': 'Initializing flask bcrypt similar to sql alchemy.', 'duration': 26.694, 'max_score': 251.496, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0251496.jpg'}, {'end': 652.867, 'src': 'embed', 'start': 628.215, 'weight': 1, 'content': [{'end': 633.996, 'text': 'So currently, our registration form will validate against things like bad emails and empty fields.', 'start': 628.215, 'duration': 5.781}, {'end': 641.159, 'text': "But there's nothing stopping a user from trying to sign up with a username or email that already exists in our database.", 'start': 634.317, 'duration': 6.842}, {'end': 652.867, 'text': "Now we have a restriction set on our database models that say that those have to be unique but that won't be caught or throw an error until we try to add that new user to the database.", 'start': 641.5, 'duration': 11.367}], 'summary': 'Registration form validates against bad emails and empty fields, but does not prevent duplicate usernames or emails in the database.', 'duration': 24.652, 'max_score': 628.215, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0628215.jpg'}], 'start': 80.461, 'title': 'Flask bcrypt password hashing', 'summary': 'Discusses the process of hashing and verifying passwords using the flask bcrypt extension, including the generation of password hashes, comparison of hashes, and implementation in a web application, with a demonstration of user registration and validation against existing credentials.', 'chapters': [{'end': 687.878, 'start': 80.461, 'title': 'Flask bcrypt password hashing', 'summary': 'Discusses the process of hashing and verifying passwords using the flask bcrypt extension, including the generation of password hashes, comparison of hashes, and implementation in a web application, with a demonstration of user registration and validation against existing credentials.', 'duration': 607.417, 'highlights': ['The process of hashing and verifying passwords using the Flask Bcrypt extension is discussed, including the generation of password hashes, comparison of hashes, and implementation in a web application. The chapter covers the usage of the Flask Bcrypt extension to hash passwords, generate password hashes, and compare hashes for verification, along with the implementation of these processes in a web application for user registration and validation.', 'Demonstration of user registration and validation against existing credentials is provided, showcasing the process of hashing passwords and adding users to the database, with an emphasis on unique username and email constraints. The chapter provides a demonstration of user registration, hashing passwords, and adding users to the database, highlighting the validation against existing credentials and addressing unique username and email constraints in the registration process.', 'The generation of password hashes and their comparison are described, showcasing the ability to create different hashes for the same password, preventing the use of hash tables for password cracking. The chapter explains the generation of password hashes and their comparison, emphasizing the generation of different hashes for the same password, thereby thwarting the use of hash tables for password cracking and enhancing security.']}], 'duration': 607.417, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv080461.jpg', 'highlights': ['The chapter covers the usage of the Flask Bcrypt extension to hash passwords, generate password hashes, and compare hashes for verification, along with the implementation of these processes in a web application for user registration and validation.', 'The chapter provides a demonstration of user registration, hashing passwords, and adding users to the database, highlighting the validation against existing credentials and addressing unique username and email constraints in the registration process.', 'The chapter explains the generation of password hashes and their comparison, emphasizing the generation of different hashes for the same password, thereby thwarting the use of hash tables for password cracking and enhancing security.']}, {'end': 1158.532, 'segs': [{'end': 738.614, 'src': 'embed', 'start': 710.595, 'weight': 0, 'content': [{'end': 714.718, 'text': 'This information can be extremely useful for debugging problems in your application,', 'start': 710.595, 'duration': 4.123}, {'end': 722.964, 'text': "but this is also why you want to be absolutely sure that you're never running in debug mode when you deploy your website publicly,", 'start': 714.718, 'duration': 8.246}, {'end': 726.346, 'text': 'because this is just too much information to expose to other people.', 'start': 722.964, 'duration': 3.382}, {'end': 733.031, 'text': 'You can actually come to the bottom of the stack trace and run Python code to dig further into the problem.', 'start': 727.207, 'duration': 5.824}, {'end': 738.614, 'text': "And you need the debugger pin from your console to do this, but it's still risky having that capability.", 'start': 733.391, 'duration': 5.223}], 'summary': 'Debugging information is useful, but risky in public deployment. accessing stack trace and running python code can be risky.', 'duration': 28.019, 'max_score': 710.595, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0710595.jpg'}, {'end': 826.981, 'src': 'embed', 'start': 805.813, 'weight': 3, 'content': [{'end': 818.878, 'text': "Now you might think that it's best to go into our register route here and add in some database checks after our form is validated to see if the username or email already exists in our database.", 'start': 805.813, 'duration': 13.065}, {'end': 820.518, 'text': 'And that would be one way to do it.', 'start': 819.218, 'duration': 1.3}, {'end': 826.981, 'text': 'But I think that the best way to do this would be to add our own custom validation for the register form.', 'start': 820.878, 'duration': 6.103}], 'summary': 'Adding custom validation for register form is the best approach.', 'duration': 21.168, 'max_score': 805.813, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0805813.jpg'}, {'end': 971.845, 'src': 'heatmap', 'start': 932.836, 'weight': 0.761, 'content': [{'end': 936.138, 'text': 'So first we need to import the user model from our models.', 'start': 932.836, 'duration': 3.302}, {'end': 937.139, 'text': 'So from the top.', 'start': 936.298, 'duration': 0.841}, {'end': 946.346, 'text': 'here I will say from flaskblog.models, import user and now go back to our conditional.', 'start': 937.139, 'duration': 9.207}, {'end': 955.214, 'text': 'and now we can query whether the username being submitted to the form is already in our database by saying of above the conditional.', 'start': 946.346, 'duration': 8.868}, {'end': 964.601, 'text': "here we'll say user is equal to user dot query, dot filter by and we want to filter by.", 'start': 955.214, 'duration': 9.387}, {'end': 971.845, 'text': "if this username is already in the database, we'll say username is equal to username dot data.", 'start': 964.601, 'duration': 7.244}], 'summary': 'Import user model from flaskblog.models and query if username already in database.', 'duration': 39.009, 'max_score': 932.836, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0932836.jpg'}, {'end': 1032.391, 'src': 'embed', 'start': 996.722, 'weight': 5, 'content': [{'end': 998.804, 'text': "So I'll get rid of these empty spaces here.", 'start': 996.722, 'duration': 2.082}, {'end': 1007.291, 'text': "So we'll just say if user, whoops, if user, user, then we want to raise the validation error.", 'start': 999.144, 'duration': 8.147}, {'end': 1011.074, 'text': "So basically, if user is none, then it won't hit this conditional.", 'start': 1007.591, 'duration': 3.483}, {'end': 1015.177, 'text': 'But if user is anything other than none, then it will throw this validation error.', 'start': 1011.414, 'duration': 3.763}, {'end': 1018.56, 'text': 'Now the validation message is what gets sent back to the forum.', 'start': 1015.457, 'duration': 3.103}, {'end': 1022.823, 'text': 'So we want to be more specific so that the user knows what actually went wrong.', 'start': 1018.6, 'duration': 4.223}, {'end': 1032.391, 'text': 'So we want to say that username is taken, please choose a different one.', 'start': 1023.163, 'duration': 9.228}], 'summary': 'Code checks if user is none, then raises validation error with specific message', 'duration': 35.669, 'max_score': 996.722, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0996722.jpg'}, {'end': 1064.529, 'src': 'embed', 'start': 1039.755, 'weight': 4, 'content': [{'end': 1048.319, 'text': "we haven't actually imported this validation error yet, so that needs to be done as well, and that is part of the wtforms validator.", 'start': 1039.755, 'duration': 8.564}, {'end': 1051.823, 'text': 'so we can just add that to the import there.', 'start': 1048.319, 'duration': 3.504}, {'end': 1057.226, 'text': 'so, from wtforms.validators, add that validation error there onto the import.', 'start': 1051.823, 'duration': 5.403}, {'end': 1061.387, 'text': 'okay, so that should give us a validation error if the username is already taken.', 'start': 1057.666, 'duration': 3.721}, {'end': 1064.529, 'text': 'now we want the email to be unique too.', 'start': 1061.387, 'duration': 3.142}], 'summary': 'Import validation error from wtforms.validators for username uniqueness and also for email uniqueness.', 'duration': 24.774, 'max_score': 1039.755, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01039755.jpg'}], 'start': 688.559, 'title': 'Debugging in flask and custom validation', 'summary': 'Discusses the risks and benefits of flask debug mode, emphasizing the need to avoid running in production, as well as the implementation of custom validation methods in a registration form to prevent duplicate entries and enhance user experience.', 'chapters': [{'end': 805.493, 'start': 688.559, 'title': 'Debugging in flask and the risks of debug mode', 'summary': 'Discusses the usefulness of error screens in flask debug mode for debugging applications, but also highlights the risk of exposing too much information to the public, emphasizing the need to avoid running in debug mode in production.', 'duration': 116.934, 'highlights': ['Flask error screens provide valuable information for debugging problems in applications, but running in debug mode when deploying publicly exposes too much information.', 'The ability to run Python code at the bottom of the stack trace using the debugger pin can help dig further into the problem, but it poses a security risk.', "In debug mode, it's possible to run Python code within the browser to inspect variables and debug certain problems, but running in production debug mode is strongly discouraged."]}, {'end': 1158.532, 'start': 805.813, 'title': 'Custom validation for registration form', 'summary': 'Discusses the implementation of custom validation methods in a registration form to check for the existence of usernames and emails in the database before form submission, resulting in the prevention of duplicate entries and improved user experience.', 'duration': 352.719, 'highlights': ['Implemented custom validation methods for username and email fields in the registration form to check for existing entries in the database before form submission. Prevent duplicate entries, Improve user experience', 'Utilized WTForm documentation to create custom validation functions within the registration form for checking the existence of usernames and emails in the database. Utilized WTForm documentation, Custom validation functions', "Added specific error messages for validation failures, such as 'username is taken, please choose a different one' and 'email is taken, please choose a different one', to provide clear feedback to users. Clear error messages, Improved user feedback"]}], 'duration': 469.973, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv0688559.jpg', 'highlights': ['Flask error screens provide valuable debugging information, but avoid debug mode in production.', 'Debugger pin allows running Python code at stack trace bottom, but poses a security risk.', 'Running in production debug mode is strongly discouraged to prevent exposing too much information.', 'Implemented custom validation methods in registration form to prevent duplicate entries.', 'Utilized WTForm documentation to create custom validation functions for username and email fields.', 'Added specific error messages for validation failures to provide clear feedback to users.']}, {'end': 1406.071, 'segs': [{'end': 1219.33, 'src': 'heatmap', 'start': 1158.912, 'weight': 0, 'content': [{'end': 1167.817, 'text': "So those are working and we were able to query our database and tell the user that this username or email was already taken and that they'll need to choose something different.", 'start': 1158.912, 'duration': 8.905}, {'end': 1170.759, 'text': 'Okay, so now we have a pretty good registration system.', 'start': 1168.138, 'duration': 2.621}, {'end': 1177.003, 'text': 'Now we need to create a login system so that our users that have created accounts can log in and log out.', 'start': 1171.179, 'duration': 5.824}, {'end': 1183.126, 'text': "Now to do this, we're going to be using another Flask extension, and this extension is called Flask Login,", 'start': 1177.363, 'duration': 5.763}, {'end': 1185.508, 'text': 'and it makes it really easy to manage user sessions.', 'start': 1183.126, 'duration': 2.382}, {'end': 1189.591, 'text': "So first, let's install that by using pip.", 'start': 1185.908, 'duration': 3.683}, {'end': 1196.756, 'text': "So I'm going to open our command line here and I'm going to shut down server by hitting control C and clearing this out.", 'start': 1189.911, 'duration': 6.845}, {'end': 1202.701, 'text': 'And we can install this just by saying pip install flask dash login.', 'start': 1197.137, 'duration': 5.564}, {'end': 1207.002, 'text': "And once we have that installed, I'll clear the screen here.", 'start': 1204.5, 'duration': 2.502}, {'end': 1213.346, 'text': "And now let's add this to our initialization of our application like we've done with our other extensions.", 'start': 1207.362, 'duration': 5.984}, {'end': 1219.33, 'text': "So I'll open up our code here and go to our init.py file within our package.", 'start': 1213.646, 'duration': 5.684}], 'summary': 'Implemented registration system and now setting up a login system using flask login for user sessions management.', 'duration': 43.789, 'max_score': 1158.912, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01158912.jpg'}, {'end': 1287.313, 'src': 'heatmap', 'start': 1246.323, 'weight': 3, 'content': [{'end': 1247.463, 'text': 'into that class.', 'start': 1246.323, 'duration': 1.14}, {'end': 1251.764, 'text': "okay, so now we're ready to use this login manager in our application.", 'start': 1247.463, 'duration': 4.301}, {'end': 1261.406, 'text': 'so the way that this works is that we add some functionality to our database models and then it will handle all of the sessions in the background for us.', 'start': 1251.764, 'duration': 9.642}, {'end': 1263.867, 'text': "so let's open up our database model.", 'start': 1261.406, 'duration': 2.461}, {'end': 1266.427, 'text': "so i'll open up this models.py file here.", 'start': 1263.867, 'duration': 2.56}, {'end': 1274.289, 'text': 'and first of all, we need to import our login manager from our package and that can comes from the same place as our db instance.', 'start': 1266.427, 'duration': 7.862}, {'end': 1275.949, 'text': 'so we can just add that to our import.', 'start': 1274.289, 'duration': 1.66}, {'end': 1282.571, 'text': 'So I will add the login manager to our imports there from our flask blog package.', 'start': 1276.389, 'duration': 6.182}, {'end': 1287.313, 'text': 'And now we need to create a function with a decorator called user loader.', 'start': 1282.912, 'duration': 4.401}], 'summary': 'Using login manager to handle sessions in database models.', 'duration': 39.85, 'max_score': 1246.323, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01246323.jpg'}, {'end': 1342.606, 'src': 'embed', 'start': 1311.343, 'weight': 2, 'content': [{'end': 1317.025, 'text': 'So we can create a function called load user that takes a user ID as an argument.', 'start': 1311.343, 'duration': 5.682}, {'end': 1317.965, 'text': "So I'll do that now.", 'start': 1317.345, 'duration': 0.62}, {'end': 1319.706, 'text': 'So load user.', 'start': 1318.225, 'duration': 1.481}, {'end': 1329.256, 'text': 'that takes a user ID as our argument and then we can return the user for that ID and if you remember from a couple of videos ago,', 'start': 1320.186, 'duration': 9.07}, {'end': 1332.08, 'text': 'we can do this with the query.get method.', 'start': 1329.256, 'duration': 2.824}, {'end': 1334.182, 'text': "so I'll say return user.get.", 'start': 1332.08, 'duration': 2.102}, {'end': 1342.606, 'text': "query dot, get and we want to get the user with that ID and let's cast that to an integer, just to be sure.", 'start': 1335.243, 'duration': 7.363}], 'summary': "Create a function 'load user' to return user for given id using query.get method.", 'duration': 31.263, 'max_score': 1311.343, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01311343.jpg'}, {'end': 1388.208, 'src': 'embed', 'start': 1361.373, 'weight': 6, 'content': [{'end': 1366.515, 'text': 'this is going to be login manager dot, user underscore loader.', 'start': 1361.373, 'duration': 5.142}, {'end': 1370.958, 'text': "Okay, so we've almost got this extension set up, but there's one more thing that we have to do.", 'start': 1366.935, 'duration': 4.023}, {'end': 1376.902, 'text': 'So the extension will expect your user model to have certain attributes and methods.', 'start': 1371.298, 'duration': 5.604}, {'end': 1379.563, 'text': "It's going to expect four to be exact.", 'start': 1377.322, 'duration': 2.241}, {'end': 1385.927, 'text': "One is called is authenticated, which will return true if they've provided valid credentials.", 'start': 1380.043, 'duration': 5.884}, {'end': 1388.208, 'text': 'Another is called is active.', 'start': 1386.347, 'duration': 1.861}], 'summary': 'Login manager requires user model with 4 attributes and methods.', 'duration': 26.835, 'max_score': 1361.373, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01361373.jpg'}], 'start': 1158.912, 'title': 'Implementing flask login system', 'summary': 'Covers creating a login system with flask, using flask-login for session management, and implementing user reloading functionality for an extension. it details the installation, initialization, and usage of flask-login, along with the addition of functionality, user loader decorator, and expected attributes and methods for the user model.', 'chapters': [{'end': 1223.672, 'start': 1158.912, 'title': 'Creating login system with flask', 'summary': 'Discusses the implementation of a registration system using flask and the installation and initialization of flask login to manage user sessions for creating a login system.', 'duration': 64.76, 'highlights': ['Flask Login extension is used to manage user sessions, making it easier to create a login system.', 'The implementation of a registration system using Flask was successful in querying the database and notifying users of already taken usernames or emails.']}, {'end': 1287.313, 'start': 1223.872, 'title': 'Using flask-login for session management', 'summary': "Covers importing and using flask-login's login manager to handle sessions in the background for database models, requiring the addition of functionality and a user loader decorator to the application.", 'duration': 63.441, 'highlights': ['Flask-Login: Importing and using the login manager allows for session handling and management of database models with added functionality and user loader decorator.', 'Creating Instance of Login Manager: Setting up an instance of the login manager for use in the application to manage sessions in the background.', 'Adding Functionality to Database Models: The process involves adding functionality to database models to enable the handling of sessions in the background.']}, {'end': 1406.071, 'start': 1287.753, 'title': 'Implementing user reloading for extension', 'summary': "Covers implementing user reloading functionality for an extension, including creating a decorated function 'load user' to retrieve a user by id using query.get method and decorating the function with 'login manager.user_loader' to specify it as the function to get a user by an id. it also explains the expected attributes and methods for the user model by the extension.", 'duration': 118.318, 'highlights': ["Creating a decorated function 'load user' to retrieve a user by ID using query.get method and decorating the function with 'login manager.user_loader' to specify it as the function to get a user by an ID.", "The extension expects the user model to have certain attributes and methods - 'is authenticated', 'is active', 'is anonymous', and a method called 'get ID'."]}], 'duration': 247.159, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01158912.jpg', 'highlights': ['Flask Login extension is used to manage user sessions, making it easier to create a login system.', 'The implementation of a registration system using Flask was successful in querying the database and notifying users of already taken usernames or emails.', "Creating a decorated function 'load user' to retrieve a user by ID using query.get method and decorating the function with 'login manager.user_loader' to specify it as the function to get a user by an ID.", 'Flask-Login: Importing and using the login manager allows for session handling and management of database models with added functionality and user loader decorator.', 'Creating Instance of Login Manager: Setting up an instance of the login manager for use in the application to manage sessions in the background.', 'Adding Functionality to Database Models: The process involves adding functionality to database models to enable the handling of sessions in the background.', "The extension expects the user model to have certain attributes and methods - 'is authenticated', 'is active', 'is anonymous', and a method called 'get ID'."]}, {'end': 1765.558, 'segs': [{'end': 1454.626, 'src': 'heatmap', 'start': 1406.411, 'weight': 0, 'content': [{'end': 1413.593, 'text': 'so we can simply import this class from flask login and this class is called user mixin.', 'start': 1406.411, 'duration': 7.182}, {'end': 1422.297, 'text': "so i'll say from flask underscore login, import user mixin and spell that correctly And save that.", 'start': 1413.593, 'duration': 8.704}, {'end': 1427.661, 'text': 'And then in our user model, we can simply import from this user mixin class.', 'start': 1422.617, 'duration': 5.044}, {'end': 1431.645, 'text': 'So I will just pass that in as a class that we inherit from.', 'start': 1427.981, 'duration': 3.664}, {'end': 1437.309, 'text': "Now be sure that you're still inheriting from both DB model and user mixin.", 'start': 1431.925, 'duration': 5.384}, {'end': 1439.211, 'text': "You don't want to overwrite the DB model.", 'start': 1437.329, 'duration': 1.882}, {'end': 1445.617, 'text': 'Okay, so that should be all we need to do with our extension in order for it to manage our sessions for us.', 'start': 1439.992, 'duration': 5.625}, {'end': 1450.502, 'text': "So now let's modify the login route so that we can see how this works.", 'start': 1445.958, 'duration': 4.544}, {'end': 1454.626, 'text': "So let's pull up our routes again and go to our login route.", 'start': 1450.662, 'duration': 3.964}], 'summary': 'Import user mixin from flask login and modify login route.', 'duration': 48.215, 'max_score': 1406.411, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01406411.jpg'}, {'end': 1519.601, 'src': 'embed', 'start': 1483.48, 'weight': 3, 'content': [{'end': 1486.281, 'text': "And now let's put in our logic for logging in a user.", 'start': 1483.48, 'duration': 2.801}, {'end': 1489.904, 'text': "So first of all, they'll be logging in with their email.", 'start': 1486.821, 'duration': 3.083}, {'end': 1493.628, 'text': "So let's query our database to make sure that the user exists.", 'start': 1490.225, 'duration': 3.403}, {'end': 1502.157, 'text': 'So I can say user is equal to user.query.filterby, spell that right.', 'start': 1494.008, 'duration': 8.149}, {'end': 1510.668, 'text': 'And we want to check if their email is equal to form.email.data.', 'start': 1503.178, 'duration': 7.49}, {'end': 1519.601, 'text': 'So the data that the user entered into the email form, we want to filter if there are any emails in our database with that same email address.', 'start': 1511.049, 'duration': 8.552}], 'summary': 'Logic for user login: query database for user by email.', 'duration': 36.121, 'max_score': 1483.48, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01483480.jpg'}, {'end': 1561.99, 'src': 'embed', 'start': 1528.407, 'weight': 4, 'content': [{'end': 1537.713, 'text': "And now I'm going to create a conditional that simultaneously checks that the user exists and that their password verifies with what they have in the database.", 'start': 1528.407, 'duration': 9.306}, {'end': 1557.066, 'text': 'and now we want to compare their database password with the password that they entered into the form.', 'start': 1550.542, 'duration': 6.524}, {'end': 1561.99, 'text': 'So first we pass in the hash password to this check password hash method.', 'start': 1557.386, 'duration': 4.604}], 'summary': 'Creating a conditional to verify user and password match with database.', 'duration': 33.583, 'max_score': 1528.407, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01528407.jpg'}, {'end': 1608.971, 'src': 'embed', 'start': 1582.967, 'weight': 5, 'content': [{'end': 1590.928, 'text': "So if the user exists and the password that they entered is valid with what's in the database, then we want to log that user in.", 'start': 1582.967, 'duration': 7.961}, {'end': 1597.69, 'text': 'So to log them in using our flask login extension, we need to import the login user function.', 'start': 1591.348, 'duration': 6.342}, {'end': 1605.631, 'text': "So I'll go up here to the top and we can simply say from flask underscore login import.", 'start': 1597.81, 'duration': 7.821}, {'end': 1608.971, 'text': 'We want to import this login user function.', 'start': 1606.111, 'duration': 2.86}], 'summary': 'Validating user credentials and logging in using flask login extension.', 'duration': 26.004, 'max_score': 1582.967, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01582967.jpg'}, {'end': 1622.92, 'src': 'heatmap', 'start': 1582.967, 'weight': 1, 'content': [{'end': 1590.928, 'text': "So if the user exists and the password that they entered is valid with what's in the database, then we want to log that user in.", 'start': 1582.967, 'duration': 7.961}, {'end': 1597.69, 'text': 'So to log them in using our flask login extension, we need to import the login user function.', 'start': 1591.348, 'duration': 6.342}, {'end': 1605.631, 'text': "So I'll go up here to the top and we can simply say from flask underscore login import.", 'start': 1597.81, 'duration': 7.821}, {'end': 1608.971, 'text': 'We want to import this login user function.', 'start': 1606.111, 'duration': 2.86}, {'end': 1615.234, 'text': "So let's copy this, go back down to our conditional And now we'll simply use this function to log the user in.", 'start': 1609.371, 'duration': 5.863}, {'end': 1622.92, 'text': 'So we can paste this in here and what we want to log in this user,', 'start': 1615.635, 'duration': 7.285}], 'summary': 'To log in a user with valid credentials, import and use the login user function from the flask login extension.', 'duration': 39.953, 'max_score': 1582.967, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01582967.jpg'}, {'end': 1702.942, 'src': 'embed', 'start': 1675.45, 'weight': 6, 'content': [{'end': 1679.45, 'text': "And I actually just realized that we're not logging in by username, we're logging in by email.", 'start': 1675.45, 'duration': 4}, {'end': 1681.731, 'text': 'So that should be check email and password.', 'start': 1679.47, 'duration': 2.261}, {'end': 1687.054, 'text': "So if we don't hit this conditional here, then we just want to flash this message.", 'start': 1682.531, 'duration': 4.523}, {'end': 1695.198, 'text': "So we'll put in an else and then indent that flash message into the else block there.", 'start': 1687.334, 'duration': 7.864}, {'end': 1702.942, 'text': "So if it wasn't a successful login, then they'll never hit this return statement here and they'll just end up down here at the bottom,", 'start': 1695.478, 'duration': 7.464}], 'summary': 'Login process should check email and password, and display flash message if unsuccessful.', 'duration': 27.492, 'max_score': 1675.45, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01675450.jpg'}], 'start': 1406.411, 'title': 'Session management and database login logic', 'summary': "Explains using the 'user mixin' class for session management in flask login and implementing database login logic, covering querying, password validation, login handling, flashed messages, and redirection upon successful login.", 'chapters': [{'end': 1454.626, 'start': 1406.411, 'title': 'Using user mixin for session management', 'summary': "Explains how to use the 'user mixin' class from flask login to manage sessions, including importing the class, inheriting from it in the user model, and modifying the login route.", 'duration': 48.215, 'highlights': ["Explaining the 'user mixin' class and its usage The chapter discusses importing the 'user mixin' class from Flask Login and incorporating it into the user model for session management.", 'Inheriting from both DB model and user mixin It emphasizes the importance of inheriting from both the DB model and user mixin to avoid overwriting the DB model, ensuring proper functionality.', 'Modifying the login route to utilize session management The chapter mentions the need to modify the login route in order to observe the functionality of the session management, demonstrating practical application.']}, {'end': 1765.558, 'start': 1455.007, 'title': 'Database login logic', 'summary': 'Discusses implementing database login logic, including querying the database for user credentials, validating passwords, and logging in users using flask. it also covers handling unsuccessful login attempts with flashed messages and redirecting users upon successful login.', 'duration': 310.551, 'highlights': ['Implemented logic to query the database for user credentials, ensuring that the user exists by checking the email entered in the form against the emails in the database. Database query for user existence', 'Developed conditional to verify the existence of the user and validate the password entered in the form against the hashed password stored in the database. Validation of user password', "Utilized Flask's login user function to successfully log in the user and redirected them to the home page upon successful login. Successful user login and redirection", 'Handled unsuccessful login attempts by flashing a message prompting the user to check their email and password, and appropriately redirected them to the login page. Handling of unsuccessful login attempts']}], 'duration': 359.147, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01406411.jpg', 'highlights': ["Explaining the 'user mixin' class and its usage The chapter discusses importing the 'user mixin' class from Flask Login and incorporating it into the user model for session management.", 'Inheriting from both DB model and user mixin It emphasizes the importance of inheriting from both the DB model and user mixin to avoid overwriting the DB model, ensuring proper functionality.', 'Modifying the login route to utilize session management The chapter mentions the need to modify the login route in order to observe the functionality of the session management, demonstrating practical application.', 'Implemented logic to query the database for user credentials, ensuring that the user exists by checking the email entered in the form against the emails in the database. Database query for user existence', 'Developed conditional to verify the existence of the user and validate the password entered in the form against the hashed password stored in the database. Validation of user password', "Utilized Flask's login user function to successfully log in the user and redirected them to the home page upon successful login. Successful user login and redirection", 'Handled unsuccessful login attempts by flashing a message prompting the user to check their email and password, and appropriately redirected them to the login page. Handling of unsuccessful login attempts']}, {'end': 2501.131, 'segs': [{'end': 1876.966, 'src': 'heatmap', 'start': 1766.359, 'weight': 0, 'content': [{'end': 1767.18, 'text': "Okay, so that's good.", 'start': 1766.359, 'duration': 0.821}, {'end': 1771.245, 'text': "So we're actually logging in users who exist in our database.", 'start': 1767.22, 'duration': 4.025}, {'end': 1775.952, 'text': "Now there's only a couple of other things that we need to set up here and we'll be finished up with this part.", 'start': 1771.526, 'duration': 4.426}, {'end': 1785.234, 'text': "So one thing that's a little strange here is that we're logged in, but we can still see our login and register routes in our navigation bar.", 'start': 1776.692, 'duration': 8.542}, {'end': 1791.715, 'text': "So if we click on one of those routes, then we can see that we can get back to the login page, even though we're already logged in.", 'start': 1785.534, 'duration': 6.181}, {'end': 1797.896, 'text': 'So really, if the user is already logged in and they try to go to the login or register page,', 'start': 1792.195, 'duration': 5.701}, {'end': 1800.936, 'text': 'then we should probably just redirect them back to the homepage,', 'start': 1797.896, 'duration': 3.04}, {'end': 1804.737, 'text': "because they don't need to be on those pages if they're already logged into their account.", 'start': 1800.936, 'duration': 3.801}, {'end': 1813.04, 'text': 'So in order to tell if the user is currently logged in, then we can use the current user variable from the flask login extension.', 'start': 1805.437, 'duration': 7.603}, {'end': 1815.881, 'text': "So let's go back to our routes and import that.", 'start': 1813.26, 'duration': 2.621}, {'end': 1820.343, 'text': 'So I will open up our routes, go up to the top of our import here.', 'start': 1816.121, 'duration': 4.222}, {'end': 1828.712, 'text': "And where we're importing from this flask login, let's also import current underscore user.", 'start': 1821.023, 'duration': 7.689}, {'end': 1834.398, 'text': "And now at the top of both of our login and register routes, I'll do the register route first.", 'start': 1829.132, 'duration': 5.266}, {'end': 1842.787, 'text': 'At the very top here, I will just say if the current user is authenticated.', 'start': 1834.978, 'duration': 7.809}, {'end': 1850.69, 'text': 'then we want to return a redirect for the homepage.', 'start': 1844.707, 'duration': 5.983}, {'end': 1857.172, 'text': 'So I will do a redirect URL for, and we will send them back to the homepage.', 'start': 1850.91, 'duration': 6.262}, {'end': 1862.715, 'text': 'And I will just copy this and paste this into the top of the login route as well.', 'start': 1857.653, 'duration': 5.062}, {'end': 1867.817, 'text': "So now let's see what happens when we try to go to the login or register page if we're already logged in.", 'start': 1863.015, 'duration': 4.802}, {'end': 1869.618, 'text': 'So our web server is still running.', 'start': 1868.197, 'duration': 1.421}, {'end': 1876.966, 'text': 'So now if I go to the home page and then try to go back to the login page, then we can see we just get redirected to this home page.', 'start': 1870.158, 'duration': 6.808}], 'summary': 'Implementing redirection for logged-in users to homepage from login/register pages.', 'duration': 96.356, 'max_score': 1766.359, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01766359.jpg'}, {'end': 1909.771, 'src': 'embed', 'start': 1882.292, 'weight': 4, 'content': [{'end': 1885.556, 'text': 'That conditional and that redirect that we put in there is working.', 'start': 1882.292, 'duration': 3.264}, {'end': 1889.978, 'text': "Now it's a little strange that we even see those links in our navigation if we're logged in.", 'start': 1885.896, 'duration': 4.082}, {'end': 1894.261, 'text': "Most websites will replace those with a logout link if you're logged in.", 'start': 1890.539, 'duration': 3.722}, {'end': 1903.847, 'text': "So let's create a logout route to log out our user and then we'll display in our navigation when the user is logged in a logout route.", 'start': 1894.881, 'duration': 8.966}, {'end': 1907.789, 'text': 'So to do this, I will go back to our routes and go to the bottom here.', 'start': 1904.107, 'duration': 3.682}, {'end': 1909.771, 'text': "And now we'll create a logout route.", 'start': 1908.129, 'duration': 1.642}], 'summary': 'Implementing a logout route for logged-in users in the navigation.', 'duration': 27.479, 'max_score': 1882.292, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01882292.jpg'}, {'end': 2132.014, 'src': 'embed', 'start': 2108.471, 'weight': 5, 'content': [{'end': 2116.598, 'text': "Okay, so the last thing that we're going to be learning in this video is how to put a restriction on certain routes so that you can only go to those routes if you are logged in.", 'start': 2108.471, 'duration': 8.127}, {'end': 2119.641, 'text': "So you'll see this on certain sites all the time.", 'start': 2117.259, 'duration': 2.382}, {'end': 2124.345, 'text': 'So say that I click on a link to edit my Twitter profile or something like that.', 'start': 2119.761, 'duration': 4.584}, {'end': 2132.014, 'text': "If I'm not logged in, then it will take me to the login page and say, hey, you have to log in first before you can view this page.", 'start': 2124.785, 'duration': 7.229}], 'summary': 'Learn how to restrict routes for logged-in users.', 'duration': 23.543, 'max_score': 2108.471, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02108471.jpg'}, {'end': 2270.304, 'src': 'heatmap', 'start': 2238.076, 'weight': 0.753, 'content': [{'end': 2243.701, 'text': "And now let's add a link to this route within our navigation if the user is logged in.", 'start': 2238.076, 'duration': 5.625}, {'end': 2247.484, 'text': 'And our navigation is located in our layout template.', 'start': 2244.141, 'duration': 3.343}, {'end': 2248.264, 'text': 'We just saw this.', 'start': 2247.504, 'duration': 0.76}, {'end': 2251.707, 'text': 'So this is going to be visible if the user is logged in.', 'start': 2249.125, 'duration': 2.582}, {'end': 2258.673, 'text': 'So right above our logout link, we will copy that and we will paste in this account link.', 'start': 2251.868, 'duration': 6.805}, {'end': 2264.959, 'text': "So instead of logout, I'll say account and the URL here is going to be the URL for account.", 'start': 2258.974, 'duration': 5.985}, {'end': 2265.8, 'text': "So I'll save that.", 'start': 2265.099, 'duration': 0.701}, {'end': 2270.304, 'text': 'So now if we check if our server is still running, we need to restart that.', 'start': 2266.14, 'duration': 4.164}], 'summary': 'Added account link to navigation for logged-in users.', 'duration': 32.228, 'max_score': 2238.076, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02238076.jpg'}, {'end': 2410.577, 'src': 'heatmap', 'start': 2353.622, 'weight': 0.778, 'content': [{'end': 2358.606, 'text': 'And that decorator is going to be this login required that we just imported.', 'start': 2353.622, 'duration': 4.984}, {'end': 2362.549, 'text': 'So now our extension knows that we need to log in to access that route.', 'start': 2358.986, 'duration': 3.563}, {'end': 2366.572, 'text': 'But we also need to tell the extension where our login route is located.', 'start': 2362.849, 'duration': 3.723}, {'end': 2374.519, 'text': 'So to do this, we need to go back to our init.py file where we first initialized this application.', 'start': 2366.913, 'duration': 7.606}, {'end': 2379.002, 'text': 'And right under where we created our instance of the login manager.', 'start': 2374.839, 'duration': 4.163}, {'end': 2390.989, 'text': 'we can set the login route by saying login manager dot login view and set that equal to our login view, and this will just be login,', 'start': 2379.002, 'duration': 11.987}, {'end': 2395.071, 'text': 'and the view that we pass in here is the function name of our route.', 'start': 2390.989, 'duration': 4.082}, {'end': 2399.333, 'text': "so it's the same thing that we would pass into the URL for function.", 'start': 2395.071, 'duration': 4.262}, {'end': 2403.074, 'text': "Okay, so now let's try this again in our browser.", 'start': 2400.253, 'duration': 2.821}, {'end': 2406.556, 'text': "So I have saved all of these files that we've changed.", 'start': 2403.454, 'duration': 3.102}, {'end': 2410.577, 'text': "So I'll pull up our terminal and our web server is still running.", 'start': 2406.896, 'duration': 3.681}], 'summary': 'Configuring login route for extension to access route, using function name', 'duration': 56.955, 'max_score': 2353.622, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02353622.jpg'}], 'start': 1766.359, 'title': 'User authentication implementation', 'summary': 'Discusses setting up user authentication, redirecting logged-in users, utilizing the current user variable, implementing user authentication, redirecting authenticated users, creating a logout route, conditional link display, and access restriction based on login status using the flask login extension.', 'chapters': [{'end': 1828.712, 'start': 1766.359, 'title': 'Setting up user authentication', 'summary': "Discusses logging in users, identifying a need to redirect logged-in users from the login and register pages to the homepage, and utilizing the current user variable from the flask login extension to determine the user's login status.", 'duration': 62.353, 'highlights': ["Utilizing the current user variable from the flask login extension to determine the user's login status", 'Identifying the need to redirect logged-in users from the login and register pages to the homepage', 'Logging in users who exist in the database']}, {'end': 2501.131, 'start': 1829.132, 'title': 'Implementing user authentication', 'summary': 'Covers implementing user authentication, including redirecting authenticated users, creating a logout route, displaying links conditionally based on user authentication status, and restricting access to certain routes based on user login status using the login_required decorator from the flask login extension.', 'duration': 671.999, 'highlights': ['Created redirect for authenticated users to homepage Implemented a redirect for the homepage if the current user is authenticated, preventing access to the register and login routes, resulting in users being redirected to the homepage.', 'Implemented logout functionality and updated navigation links Created a logout route to log out the user, modified the layout template to display the logout link when the user is logged in, and successfully tested the functionality.', "Restricted access to certain routes based on user login status Implemented a route for the user's account that can only be accessed after logging in, utilized the login_required decorator from the Flask Login extension, and set the login route to redirect users to the login page if they attempt to access the account page without logging in."]}], 'duration': 734.772, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv01766359.jpg', 'highlights': ["Utilizing the current user variable from the flask login extension to determine the user's login status", 'Identifying the need to redirect logged-in users from the login and register pages to the homepage', 'Logging in users who exist in the database', 'Created redirect for authenticated users to homepage', 'Implemented logout functionality and updated navigation links', 'Restricted access to certain routes based on user login status']}, {'end': 2822.297, 'segs': [{'end': 2542.977, 'src': 'embed', 'start': 2518.923, 'weight': 2, 'content': [{'end': 2525.926, 'text': 'So it would be nice if it would just redirect us back to the page that we were trying to access before it told us that we had to log in.', 'start': 2518.923, 'duration': 7.003}, {'end': 2528.147, 'text': 'And this is easy to do as well.', 'start': 2526.406, 'duration': 1.741}, {'end': 2534.952, 'text': "Now, I don't know if you noticed this, but when we tried to access the account page and it directed us to the login first,", 'start': 2528.507, 'duration': 6.445}, {'end': 2540.015, 'text': 'it added a query parameter to the URL of the page that we were trying to access.', 'start': 2534.952, 'duration': 5.063}, {'end': 2542.977, 'text': 'So let me show what this looked like.', 'start': 2540.335, 'duration': 2.642}], 'summary': 'A request for automatic redirection to the original page after logging in, with mention of added query parameter to the url.', 'duration': 24.054, 'max_score': 2518.923, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02518923.jpg'}, {'end': 2612.006, 'src': 'embed', 'start': 2586.656, 'weight': 1, 'content': [{'end': 2593.639, 'text': "and actually, first thing, we're going to be accessing query parameters and we will need to import the request object from flask.", 'start': 2586.656, 'duration': 6.983}, {'end': 2598.141, 'text': "so first let's go to the top and import that, and this is going to be from flask.", 'start': 2593.639, 'duration': 4.502}, {'end': 2600.942, 'text': "so we've already got some imports from flask here.", 'start': 2598.141, 'duration': 2.801}, {'end': 2608.985, 'text': "so i'm just going to add on to this and i will import this request object here and then go back down to our login route.", 'start': 2600.942, 'duration': 8.043}, {'end': 2612.006, 'text': 'so now we want to get this after the user logs in.', 'start': 2608.985, 'duration': 3.021}], 'summary': 'Access query parameters with request object from flask.', 'duration': 25.35, 'max_score': 2586.656, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02586656.jpg'}, {'end': 2668.832, 'src': 'embed', 'start': 2641.107, 'weight': 3, 'content': [{'end': 2644.13, 'text': "because that would throw an error if the key doesn't exist.", 'start': 2641.107, 'duration': 3.023}, {'end': 2646.552, 'text': 'And the next parameter is going to be optional.', 'start': 2644.49, 'duration': 2.062}, {'end': 2653.438, 'text': "So if we use the get method, then it will simply return none if the next key doesn't exist.", 'start': 2647.232, 'duration': 6.206}, {'end': 2659.143, 'text': 'So be sure that you are using the get method and not the square brackets with the key like you might be used to.', 'start': 2653.578, 'duration': 5.565}, {'end': 2665.549, 'text': 'So now if that next parameter exists, the next page will be equal to that route.', 'start': 2659.503, 'duration': 6.046}, {'end': 2668.832, 'text': "But if it doesn't exist, the next page is going to be none.", 'start': 2666.069, 'duration': 2.763}], 'summary': "Using the get method to handle optional parameters and prevent errors when the key doesn't exist.", 'duration': 27.725, 'max_score': 2641.107, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02641107.jpg'}, {'end': 2719.346, 'src': 'embed', 'start': 2694.692, 'weight': 4, 'content': [{'end': 2700.716, 'text': 'now some of you might not be familiar with this and Python, but this is called a ternary conditional.', 'start': 2694.692, 'duration': 6.024}, {'end': 2710.862, 'text': "basically we're just saying redirect to the next page if next page exist, but if it is none or false, then just return the redirect to this homepage.", 'start': 2700.716, 'duration': 10.146}, {'end': 2713.103, 'text': 'Okay, so that should do it for our changes.', 'start': 2711.242, 'duration': 1.861}, {'end': 2719.346, 'text': "So now let's be sure that we save all of these changes and then pull up our browser.", 'start': 2713.503, 'duration': 5.843}], 'summary': 'Introducing ternary conditional in python for redirecting to next page or homepage based on existence', 'duration': 24.654, 'max_score': 2694.692, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02694692.jpg'}, {'end': 2787.891, 'src': 'embed', 'start': 2748.946, 'weight': 0, 'content': [{'end': 2749.467, 'text': "So that's good.", 'start': 2748.946, 'duration': 0.521}, {'end': 2750.227, 'text': "That's what we wanted.", 'start': 2749.507, 'duration': 0.72}, {'end': 2757.451, 'text': "Now we also probably want to make sure that it still directs us to the homepage if the next parameter doesn't exist in the URL.", 'start': 2750.607, 'duration': 6.844}, {'end': 2762.014, 'text': "So let's log out and simply go to the login page.", 'start': 2757.791, 'duration': 4.223}, {'end': 2770.178, 'text': "And since we went there directly, this next parameter doesn't exist in the URL because we didn't try to access a page that required a login.", 'start': 2762.414, 'duration': 7.764}, {'end': 2772.84, 'text': "So now let's log in again.", 'start': 2770.619, 'duration': 2.221}, {'end': 2777.304, 'text': 'And we can see that that logs us in and directs us to the homepage.', 'start': 2774.522, 'duration': 2.782}, {'end': 2779.605, 'text': 'So all of that seems to be working well.', 'start': 2777.624, 'duration': 1.981}, {'end': 2782.127, 'text': 'Okay, so I think that is going to do it for this video.', 'start': 2780.046, 'duration': 2.081}, {'end': 2787.891, 'text': 'I hope that now you have a good idea for how you can implement an authorization system like this on your website.', 'start': 2782.447, 'duration': 5.444}], 'summary': 'Testing login functionality, redirects to homepage, and troubleshoots parameter in url.', 'duration': 38.945, 'max_score': 2748.946, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02748946.jpg'}], 'start': 2501.131, 'title': 'User redirection and authorization system implementation', 'summary': 'Covers improving user redirection by suggesting redirection to the previous page after logging in and implementing an authorization system using python. it includes the use of query parameters for redirection and the implementation of a system using the get method and ternary conditionals for successful redirection based on url parameters.', 'chapters': [{'end': 2641.107, 'start': 2501.131, 'title': 'Improving user redirection', 'summary': 'Discusses the issue of redirection after logging in, suggesting that the user should be redirected back to the page they were trying to access before being prompted to log in, with the inclusion of a query parameter in the url for this purpose.', 'duration': 139.976, 'highlights': ['The user should be redirected back to the page they were trying to access before being prompted to log in This would provide a more seamless user experience and eliminate the need to navigate back to the specific page, improving user satisfaction and potentially reducing bounce rates.', "Inclusion of a query parameter in the URL for redirection after logging in The addition of a query parameter called 'next' in the URL allows for the retrieval of the intended destination page after the user logs in, enhancing the overall usability of the login process.", "Importing the request object from flask and accessing query parameters in the login route The process involves importing the request object from Flask and accessing query parameters in the login route to retrieve the 'next' parameter from the URL, contributing to the implementation of the desired redirection functionality."]}, {'end': 2822.297, 'start': 2641.107, 'title': 'Implementing authorization system', 'summary': 'Explains the implementation of an authorization system using python, including the use of the get method for handling optional parameters and the use of ternary conditionals for redirects, ensuring successful redirection to the login page and homepage based on the existence of the next parameter in the url.', 'duration': 181.19, 'highlights': ['The chapter explains the implementation of an authorization system using Python, including the use of the get method for handling optional parameters and the use of ternary conditionals for redirects, ensuring successful redirection to the login page and homepage based on the existence of the next parameter in the URL.', "The get method is used to handle optional parameters, ensuring that it returns none if the specified key doesn't exist, providing a robust way to handle missing values in the context of the authorization system implementation.", 'Ternary conditionals are introduced, demonstrating their usage for redirects in Python, allowing for concise and efficient handling of conditional redirection based on the existence of the next page parameter in the URL.', 'The tutorial also emphasizes the importance of testing the implemented features by demonstrating the redirection behavior when accessing account pages and logging in, ensuring the expected behavior of the authorization system.', 'The author encourages engagement by inviting questions in the comment section and promoting support through actions such as liking, sharing the videos, and contributing via Patreon, fostering community interaction and support for the tutorial content.']}], 'duration': 321.166, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/CSHx6eCkmv0/pics/CSHx6eCkmv02501131.jpg', 'highlights': ["The addition of a query parameter called 'next' in the URL allows for the retrieval of the intended destination page after the user logs in, enhancing the overall usability of the login process.", "The process involves importing the request object from Flask and accessing query parameters in the login route to retrieve the 'next' parameter from the URL, contributing to the implementation of the desired redirection functionality.", 'The user should be redirected back to the page they were trying to access before being prompted to log in. This would provide a more seamless user experience and eliminate the need to navigate back to the specific page, improving user satisfaction and potentially reducing bounce rates.', "The get method is used to handle optional parameters, ensuring that it returns none if the specified key doesn't exist, providing a robust way to handle missing values in the context of the authorization system implementation.", 'Ternary conditionals are introduced, demonstrating their usage for redirects in Python, allowing for concise and efficient handling of conditional redirection based on the existence of the next page parameter in the URL.', 'The tutorial also emphasizes the importance of testing the implemented features by demonstrating the redirection behavior when accessing account pages and logging in, ensuring the expected behavior of the authorization system.']}], 'highlights': ['The chapter emphasizes the significance of using bcrypt to hash passwords for security, as plain text passwords can compromise user logins if the database is compromised.', 'The necessity of securely authenticating users for logging in and out is addressed for maintaining application security and user privacy.', 'The importance of using Flask bcrypt for easy password hashing is highlighted, with a demonstration of its installation using pip in the project directory.', 'The video focuses on the process of adding users to the database, along with the upcoming ability to create posts using the application.', 'The previous usage of plain text passwords in the examples is highlighted as a practice to avoid in actual web applications for safeguarding user data.', 'The chapter covers the usage of the Flask Bcrypt extension to hash passwords, generate password hashes, and compare hashes for verification, along with the implementation of these processes in a web application for user registration and validation.', 'The chapter provides a demonstration of user registration, hashing passwords, and adding users to the database, highlighting the validation against existing credentials and addressing unique username and email constraints in the registration process.', 'The chapter explains the generation of password hashes and their comparison, emphasizing the generation of different hashes for the same password, thereby thwarting the use of hash tables for password cracking and enhancing security.', 'Flask error screens provide valuable debugging information, but avoid debug mode in production.', 'Debugger pin allows running Python code at stack trace bottom, but poses a security risk.', 'Running in production debug mode is strongly discouraged to prevent exposing too much information.', 'Implemented custom validation methods in registration form to prevent duplicate entries.', 'Utilized WTForm documentation to create custom validation functions for username and email fields.', 'Added specific error messages for validation failures to provide clear feedback to users.', 'Flask Login extension is used to manage user sessions, making it easier to create a login system.', 'The implementation of a registration system using Flask was successful in querying the database and notifying users of already taken usernames or emails.', "Creating a decorated function 'load user' to retrieve a user by ID using query.get method and decorating the function with 'login manager.user_loader' to specify it as the function to get a user by an ID.", 'Flask-Login: Importing and using the login manager allows for session handling and management of database models with added functionality and user loader decorator.', 'Creating Instance of Login Manager: Setting up an instance of the login manager for use in the application to manage sessions in the background.', 'Adding Functionality to Database Models: The process involves adding functionality to database models to enable the handling of sessions in the background.', "The extension expects the user model to have certain attributes and methods - 'is authenticated', 'is active', 'is anonymous', and a method called 'get ID'.", "Explaining the 'user mixin' class and its usage The chapter discusses importing the 'user mixin' class from Flask Login and incorporating it into the user model for session management.", 'Inheriting from both DB model and user mixin It emphasizes the importance of inheriting from both the DB model and user mixin to avoid overwriting the DB model, ensuring proper functionality.', 'Modifying the login route to utilize session management The chapter mentions the need to modify the login route in order to observe the functionality of the session management, demonstrating practical application.', 'Implemented logic to query the database for user credentials, ensuring that the user exists by checking the email entered in the form against the emails in the database. Database query for user existence', 'Developed conditional to verify the existence of the user and validate the password entered in the form against the hashed password stored in the database. Validation of user password', "Utilized Flask's login user function to successfully log in the user and redirected them to the home page upon successful login. Successful user login and redirection", 'Handled unsuccessful login attempts by flashing a message prompting the user to check their email and password, and appropriately redirected them to the login page. Handling of unsuccessful login attempts', "Utilizing the current user variable from the flask login extension to determine the user's login status", 'Identifying the need to redirect logged-in users from the login and register pages to the homepage', 'Logging in users who exist in the database', 'Created redirect for authenticated users to homepage', 'Implemented logout functionality and updated navigation links', 'Restricted access to certain routes based on user login status', "The addition of a query parameter called 'next' in the URL allows for the retrieval of the intended destination page after the user logs in, enhancing the overall usability of the login process.", "The process involves importing the request object from Flask and accessing query parameters in the login route to retrieve the 'next' parameter from the URL, contributing to the implementation of the desired redirection functionality.", 'The user should be redirected back to the page they were trying to access before being prompted to log in. This would provide a more seamless user experience and eliminate the need to navigate back to the specific page, improving user satisfaction and potentially reducing bounce rates.', "The get method is used to handle optional parameters, ensuring that it returns none if the specified key doesn't exist, providing a robust way to handle missing values in the context of the authorization system implementation.", 'Ternary conditionals are introduced, demonstrating their usage for redirects in Python, allowing for concise and efficient handling of conditional redirection based on the existence of the next page parameter in the URL.', 'The tutorial also emphasizes the importance of testing the implemented features by demonstrating the redirection behavior when accessing account pages and logging in, ensuring the expected behavior of the authorization system.']}