使用 Python,Flask 和 Angular 构建现代 Web 应用程序 - 第 2 部分¶
In this series, you will learn how to create modern web applications with Python, Flask, and Angular.
TL;DR: In this series, you will learn how to create modern web applications with Python, Flask, and Angular. You will use this stack to build a SPA and a backend API to expose exams and questions so users can test their knowledge regarding different technologies. In this GitHub repository, you can find the final code created throughout the second part of the series.
So far, this series contains three parts:
- Part 1 includes topics like bootstrapping the Flask application, managing Entities with SQLAlchemy ORM, and bootstrapping the Angular application.
- Part 2 (this one) includes topics like securing Flask Apps, handling Angular forms, and securing Angular Apps.
- Part 3 includes topics like configuring Angular Material, handling Authorization, and migrating Databases with Alembic.
你将要建立什么¶
在本系列中,您将使用 Python,Flask 和 Angular 构建基于现代架构的 Web 应用程序。 使用 Angular,您将构建一个 SPA(单页应用程序),允许用户浏览考试和问题。 这些用户在通过身份验证后,将能够通过选择问题所揭示的多个选项之一来测试他们关于特定主题的知识。 然后,当您的用户提交他们的答案时,您的后端将检查他们是对还是错,记录结果,并将此结果发回给用户。
在本系列的这一部分中,您将首先将 Auth0 配置为应用程序的身份管理系统。 您将配置 Auth0 API 来表示和保护您的 Flask 应用程序,您将配置 Auth0 应用程序来表示和保护您的 Angular SPA。 使用 Auth0 保护您的应用程序后,您将增强应用程序以允许用户测试他们的知识。
使用 Auth0 管理身份¶
Instead of investing time to develop rudimentary authentication mechanisms to manage the identity of your users, you are going to use Auth0. For startup projects like this one, the free tier provided by Auth0 is more than enough. Besides being free, by choosing Auth0, you will get a modern, easy to use, and reliable service capable of integrating with tons of different social identity providers (e.g. Facebook, Google, Twitter, etc). Also, if you ever need to integrate with enterprise identity providers using protocols like OpenID Connect, SAML, and WS-Federation, don’t worry, Auth0’s got you covered.
That is, Auth0 can help you focus on what matters the most to you, the special features of your product. In addition, Auth0 can improve your product’s security with state-of-the-art features like passwordless, breached password surveillance, and multifactor authentication.
使用 Auth0 保护 Flask 应用程序¶
To integrate Auth0 into your Flask application, you will need to create an Auth0 API. If you haven’t done so yet, you can sign up for a free Auth0 account now. After creating your account, head to the APIs page on your Auth0 dashboard and click on the Create API button. When clicked, this button will bring up a form where Auth0 will ask you for three properties. The following list summarizes these properties and how to fill them:
Name: This is a friendly name to remind you what this API is about. Here, you can enter something like “Online Exam”. Identifier: This is the logical identifier (a.k.a. audience) of your API. Usually, developers use an URL to represent their APIs. Although this is not mandatory, it is a good approach. So, in this field, enter something like https://online-exam.digituz.com.br. Signing Algorithm: In this field, you will have to select between two strategies: RS256 (the default one) and HS256. The best option is to stick with the default one (RS256). If you are curious, you can check this thread to understand the difference between them. When you finish filling out this form, you can hit the Create button. This will redirect you to a tab called Quick Start inside your new Auth0 API. From there, select the Scopes tab and add a new scope called manage:exams (as a good practice, always define scopes when dealing with the OAuth 2.0 authorization mechanism). You can add a simple description like Manage exams to it. After that, you can leave this page open and head back to your Flask project (i.e. to the backend directory inside the project root).
Back in your project, you will need to create a Python decorator to wrap the endpoints that must be secured. To define this decorator, create a new file called auth.py inside the ./backend/src/ directory. Then, inside this file, paste the following code:
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 |
|
Although lengthy, this code is quite simple. Here is a list to explain what this new module does:
First, it defines three constants: AUTH0_DOMAIN, ALGORITHMS, and API_AUDIENCE. Your project will use these constants to communicate with Auth0 to validate users (tokens). Note that you will have to replace the value of these constants with the details of your Auth0 account. Second, it defines a class called AuthError. This class exists to represent errors originated in this module. Third, it defines a function called get_token_auth_header. Your app will use this function to read Authorization headers to fetch their access tokens. Lastly, this module defines the requires_auth decorator. This decorator might look complex but, if you analyze carefully, you will see that all it does is to fetch the correct public key from Auth0 to validate tokens. Instead of sharing static public keys, Auth0 uses the JWK specification to represent the cryptographic keys used for signing tokens. You can learn more about this subject here. You probably noticed that the decorator that your created is using a module called jwt that is not available to your project. To install this dependency, issue the following command inside the backend directory:
pipenv install python-jose-cryptodome Now, to use this decorator, you can update the main.py file as follows:
Note that you are securing only the add_exam function (i.e. the endpoint that accepts POST requests). The endpoint that retrieves exams will remain public so visitors can see what exams your application contains. Another important feature added by the new version of this file is the handle_auth_error function. By using the @app.errorhandler decorator, you are configuring your Flask application to call this function when AuthErrors are raised. This error handler makes errors look nice and easier to fix as they simply return a JSON object with the details.
That’s it! You Flask application is now secured with Auth0. To test it, you can issue the following commands:
Now, to get an access token to test the secured endpoint, you will need to copy a command from your Auth0 API. So, head back to the page that you left open, then click on the Test tab, and copy the first curl command shown there. The code snippet below shows how to use this command to fetch the access token and how to send it to your Flask application (replace the first command with the one you copied from your Auth0 API):
Hurray! You have a Flask application secured with a modern identity management solution. Time to save your progress:
添加表单以创建考试¶
Next, you can go back to your code. Before integrating Auth0 into your Angular app, you will add two new components to it: ExamsComponent and ExamFormComponent. The first one will render the list of exams (i.e. you will remove this functionality from the AppComponent) and the second one will allow authenticated users to create exams.
As such, open the app.component.ts file and replace all its content with this:
As you can see, this component exists only to show a title and to define where other components will be rendered (<router-outlet></router-outlet>
).
As you have moved this component’s template to this file, you can remove the app.component.html file.
Now, to show the exams list again, you are going to create the ExamsComponent. To do so, create a new file called exams.component.ts inside the src/app/exams directory with the following code:
There is nothing fancy about this component, you are simply moving the code that renders the list of exams from the AppComponent to this one and adding a button to enable users to navigate to the /new-exam page.
Speaking of which, you have to create the component that will be responsible for this URI. Therefore, create a new file called exam-form.component.ts inside the src/app/exams directory and add the following code to it:
In this component, you are defining two input elements where users will be able to inform the title and description of the exam that they are creating and a button that triggers the saveExam method. This method calls another (homonymous) method that you will define in the examsApi service. Then, if the call to this method is successful, users are redirected to the home page (/) and, if the call is unsuccessful, an alert is shown by the browser.
Now, to define the saveExam method on the ExamsApiService, open the exams-api.service.ts file and update it as follows:
With these changes in place, you can open a terminal, move to the frontend directory, and run the ng serve command. Then, if you open http://localhost:4200/ in a browser, you will see the list of exams and a button labeled New Exam. Clicking on this button, you will be redirected to your new form. The problem now is that you will get an error saying “Http failure response for http://localhost:5000/exams: 401 UNAUTHORIZED” when clicking on the Save Exam button. The reason for that is simple, you haven’t configured Auth0 in your Angular app yet.
使用 Auth0 保护 Angular 应用程序¶
To solve the 401 UNAUTHORIZED issue, the first thing you will have to do is to create an Auth0 Application to represent your Angular app. To do so, browse to the Applications page on the Auth0 dashboard and click on the Create Application button. This time, you will have to provide only two things to Auth0:
Name: Another friendly reminder, this time to your Auth0 Application. Here, you can add something like “Online Exam Application”. Application Type: The type of the application that you are creating. In this case, as you are using Angular to create a SPA, you will choose Single Page Web Applications. Creating an Auth0 Application to represent the Angular app.
Having filled out this form, click on the Create button. When finished creating your application (it takes just a second or two), Auth0 will redirect you to the Quick Start tab of the new application. From there, click on the Settings tab to inform to Auth0 what the Allowed Callback URLs are. As for the moment you are only running your app locally, you can simply add the http://localhost:4200/callback URL to this field. Now, you can hit the Save Changes button at the bottom of the page and leave it open (you will need to copy some properties from it soon).
Now, you can go back to your Angular project and integrate it with Auth0. To do so, you will have to install the auth0-web NPM package. So, open a terminal, move to the frontend directory, and issue the following command:
npm i auth0-web@1.7.0 Note: You have to use version 1.7.0 of this library as the latest version (2.X) includes breaking changes.
After installing this package, you will have to create the component responsible for handling the callback URL called by Auth0. As such, create a new file called callback.component.ts in the src/app/ directory and add the following code to it:
As you can see, this component simply shows a message saying “Loading authentication details…” to users and delegates to auth0-web the process of parsing the callback URL. Then, when auth0-web finishes its job, users are redirected to the home page (self.router.navigate(['/'])).
Next, you will have to refactor the exams.component.ts file to allow users to sign in and sign out. So, open this file and replace its code with the following:
In the new version of this component, you are adding two new buttons (Sign In and Sign Out) and a paragraph that shows names of authenticated users. All these new elements are conditionally showed according to the authenticated flag. The Sign Out and New Exam buttons are visible when this flag is set, otherwise you’ll see the Sign In button.
To make everything work, the new ExamsComponent references and calls three methods provided by auth0-web (signIn, signOut, and getProfile). Besides these methods, this component also subscribes an anonymous function to change the value of the authenticated flag whenever the authentication status changes.
After updating the ExamsComponent, you will have to update the ExamsApiService to make use of the access_token retrieved from Auth0. So, open the exams-api.service.ts file and update it as follows:
The difference to the previous version is that now you are adding the Authorization header to the POST request that is sent when users try to save a new exam. This header is the missing piece to make your Angular and your Flask apps communicate properly.
So, to wrap up everything, you will have to update your AppModule to declare the CallbackComponent, register the /callback route, and to configure the auth0-web package. As such, open the app.module.ts and change it as follows:
Note that you will have to replace the domain, audience, and clientID properties on this code with values from your Auth0 account. So, head back to your Auth0 management dashboard and copy the domain and clientID from the Auth0 Application created before and audience from the Auth0 API (that is, copy the API identifier and paste it here).
That’s it! If you run your Angular application now, you will be able to create new exams.
Developing modern applications with Python, Flask, and Angular.
Wait! Don’t forget to save your progress!!
"Securing applications with Auth0 is easy and allows me to focus on my apps features."
Tweet This
结论和后续步骤¶
在本系列的第二部分中,您将重点放在添加 Auth0 以充当 Flask 和 Angular 应用程序的身份管理服务。 您首先定义了一个代表 Flask 后端应用程序的 Auth0 API,然后在项目中添加了一个新功能(允许用户添加检查的表单),最后,您将 Auth0 集成到 Angular 应用程序中。
在下一篇文章中,您将学习如何安装和配置 Angular Material 组件,如何使用 Auth0 角色来控制用户可以执行的操作,以及如何使用 Alembic(数据库迁移工具)来管理数据库模式。
敬请关注!