本文共 18634 字,大约阅读时间需要 62 分钟。
angular 异步验证
In this tutorial, we’ll demonstrate how to set up token-based authentication (via JSON Web Tokens) with Angular 4 and Flask.
在本教程中,我们将演示如何使用Angular 4和Flask设置基于令牌的身份验证(通过JSON Web令牌)。
Main Dependencies:
主要依赖项:
Here’s the full user auth process:
这是完整的用户身份验证过程:
Start by globally installing the :
首先全局安装 :
11 |
Then generate a new Angular 4 project boilerplate:
然后生成一个新的Angular 4项目样板:
11 |
Fire up the app after the dependencies install:
安装依赖项后启动应用程序:
1122 |
It will probably take a minute or two to compile and build your application. Once done, navigate to to ensure the app is up and running.
编译和构建应用程序可能需要一两分钟。 完成后,导航到以确保该应用程序已启动并正在运行。
Open up the project in your favorite code editor, and then glance over the code:
在您喜欢的代码编辑器中打开项目,然后浏览一下代码:
11223344556677889910101111121213131414151516161717181819192020212122222323242425252626272728282929 |
In short, the client-side code lives in the “src” folder and the Angular app itself can be found in the “app” folder.
简而言之,客户端代码位于“ src”文件夹中,而Angular应用本身可在“ app”文件夹中找到。
Take note of the AppModule
within app.module.ts. This is used to bootstrap the Angular app. The @NgModule
decorator takes metadata that lets Angular know how to run the app. Everything that we create in this tutorial will be added to this object.
注意AppModule
中的AppModule。 这用于引导Angular应用程序。 @NgModule
装饰器采用元数据,该数据使Angular知道如何运行该应用程序。 我们在本教程中创建的所有内容都将添加到该对象。
Make sure you have a decent grasp of the app structure before moving on.
在继续之前,请确保您对应用程序的结构有很好的了解。
NOTE: Just getting started with Angular 4? Review the , since the app generated from the CLI follows the recommended structure from that guide, as well as the .
注意:刚开始使用Angular 4? 查看 ,因为从CLI生成的应用程序遵循该指南的推荐结构,以及 。
Did you notice that the CLI initialized a new Git repo? This part is optional, but it’s a good idea to create a new Github repository and update the remote:
您是否注意到CLI初始化了一个新的Git存储库? 这部分是可选的,但最好创建一个新的Github存储库并更新远程:
11 |
Now, let’s wire up a new …
现在,让我们连接一个新 ……
First, use the CLI to generate a new Login component:
首先,使用CLI生成一个新的Login组件:
11 |
This set up the component files and folders and even wired it up to app.module.ts. Next, let’s change the login.component.ts file to the following:
这将设置组件文件和文件夹,甚至将其连接到app.module.ts。 接下来,让我们将login.component.ts文件更改为以下内容:
11223344556677889910101111 |
If you haven’t used before, then this code probably looks pretty foreign to you. TypeScript is a statically-typed superset of JavaScript that compiles to vanilla JavaScript, and it is the de facto programming language for building Angular 4 apps.
如果您以前没有使用过 ,那么这段代码对您来说可能看起来很陌生。 TypeScript是JavaScript的静态类型超集,可编译为原始JavaScript,它是用于构建Angular 4应用程序的事实上的编程语言。
In Angular 4, we define a component by wrapping a config object with an @Component
decorator. We can share code between packages by importing the classes we need; and, in this case, we import Component
from the @angular/core
package. The LoginComponent
class is the component’s controller, and we use the export
operator to make it available for other classes to import.
在Angular 4中,我们通过使用@Component
装饰器包装配置对象来定义组件。 我们可以通过导入所需的类在程序包之间共享代码。 在这种情况下,我们从@angular/core
包中导入Component
。 LoginComponent
类是组件的控制器,我们使用export
运算符使其可用于其他类的导入。
Add the following HTML to the login.component.html:
将以下HTML添加到login.component.html中:
112233 |
Next, configure the routes, via the in the app.module.ts file:
接下来,配置路由,通过在app.module.ts文件:
11223344556677889910101111121213131414151516161717181819192020212122222323 |
Finish enabling routing by replacing all HTML in the app.component.html file with the <router-outlet>
tag:
通过使用<router-outlet>
标记替换app.component.html文件中的所有HTML,完成启用路由:
11 |
Run ng serve
in your terminal, if you haven’t already, and then navigate to . If all went well you should see the just a test
text.
如果尚未在终端中运行ng serve
,请导航至 。 如果一切顺利,您应该just a test
看到just a test
文本。
To quickly add some style, update the index.html, adding in and wrapping the <app-root></app-root>
in a :
要快速添加某种样式,请更新index.html,添加并将<app-root></app-root>
包装在 :
1122334455667788991010111112121313141415151616 |
You should see the app auto reload as soon as you save.
保存后,您应该会看到该应用程序自动重新加载。
Next, let’s create a global to handle a user logging in, logging out, and signing up:
接下来,让我们创建一个全局来处理用户登录,注销和注册:
11 |
Edit the auth.service.ts so that it has the following code:
编辑auth.service.ts,使其具有以下代码:
1122334455667788 |
Remember how providers worked in Angular 1? They were global objects that stored a single state. When the data in a provider changed, any object that had injected that provider would receive the updates. In Angular 4, providers retain their special behavior and they are defined with the @Injectable
decorator.
还记得提供商在Angular 1中的工作方式吗? 它们是存储单个状态的全局对象。 当提供程序中的数据更改时,注入该提供程序的任何对象都将接收更新。 在Angular 4中,提供程序保留其特殊行为,并使用@Injectable
装饰器进行定义。
Before adding anything significant to AuthService
, let’s make sure the service itself is wired up correctly. To do that, within login.component.ts inject the service and call the test()
method:
在向AuthService
添加重要内容之前,请确保服务本身已正确连接。 为此,在login.component.ts中注入服务并调用test()
方法:
1122334455667788991010111112121313141415151616 |
We’ve introduced some new concepts and keywords. The constructor()
function is a special method that we use to set up a new instance of a class. The constructor()
is where we pass any parameters that the class requires, including any providers (i.e., AuthService
) that we want to inject. In TypeScript, we can hide variables from the outside world with the private
keyword. Passing a private
variable in the constructor is a shortcut to defining it within the class and then assigning the argument’s value to it. Notice how the auth
variable is accessible to the this
object after it is passed into the constructor.
我们介绍了一些新概念和关键字。 constructor()
函数是一种特殊的方法,我们使用它来建立类的新实例。 constructor()
是我们传递类所需的任何参数的地方,包括我们要注入的任何提供程序(即AuthService
)。 在TypeScript中,我们可以使用private
关键字隐藏外界的变量。 在构造函数中传递private
变量是在类中定义它,然后为其分配参数值的快捷方式。 请注意,在this
对象传递到构造函数之后, auth
变量如何可访问this
对象。
We implement the OnInit
interface to ensure that we explicitly define a ngOnInit()
function. Implementing OnInit
ensures that our component will be called after the first change detection check. This function is called once when the component first initializes, making it the ideal place to configure data that relies on other Angular classes.
我们实现OnInit
接口以确保我们明确定义ngOnInit()
函数。 实施OnInit
可确保在第一次更改检测检查之后调用我们的组件。 组件首次初始化时,将调用此函数一次,使其成为配置依赖于其他Angular类的数据的理想场所。
Unlike components, which are automatically added, services have to be manually imported and configured on the @NgModule
. So, to get it working, you’ll also have to import the AuthService
in app.module.ts and add it to the providers
:
与自动添加的组件不同,必须在@NgModule
上手动导入和配置@NgModule
。 因此,要使其正常工作,您还必须在AuthService
中导入AuthService并将其添加到providers
:
112233445566778899101011111212131314141515161617171818191920202121222223232424 |
Run the server and then navigate to . You should see working
logged to the JavaScript console.
运行服务器,然后导航到 。 您应该看到将working
记录到JavaScript控制台。
To handle logging a user in, update the AuthService
like so:
要处理用户登录, AuthService
像这样更新AuthService
:
11223344556677889910101111121213131414 |
We employ the help of some built-in Angular classes, Headers
and Http
, to handle our AJAX calls to the server.
我们利用一些内置的Angular类Headers
和Http
的帮助来处理对服务器的AJAX调用。
Also, update the app.module.ts file to import the HttpModule
.
另外,更新app.module.ts文件以导入HttpModule
。
11223344556677889910101111121213131414151516161717181819192020212122222323242425252626 |
Here, we are using the Http service to send an AJAX request to the /user/login
endpoint. This returns a promise object.
在这里,我们使用Http服务将AJAX请求发送到/user/login
端点。 这将返回一个Promise对象。
NOTE: Make sure to remove
console.log(this.auth.test());
from theLoginComponent
component.注意:确保删除
console.log(this.auth.test());
从LoginComponent
组件。
Let’s go ahead and add the ability to register a user as well, which is similar to logging a user in. Update src/app/services/auth.service.ts, taking note of the register
method:
让我们继续并添加注册用户的功能,这类似于登录用户。更新src / app / services / auth.service.ts,注意register
方法:
112233445566778899101011111212131314141515161617171818 |
Now, to test this we need to set up a back end…
现在,要对此进行测试,我们需要设置一个后端…
For the server-side, we’ll use the finished project from a previous blog post, . You can view the code from the repository.
对于服务器端,我们将使用先前博客文章完成的项目。 您可以从存储库查看代码。
NOTE: Feel free to use your own server, just make sure to update the
baseURL
in theAuthService
.注意:随意使用您自己的服务器,只需确保更新
baseURL
中的AuthService
。
Clone the project structure in a new terminal window:
在新的终端窗口中克隆项目结构:
11 |
Follow the directions in the to set up the project, making sure the tests pass before moving on. Once done, run the server with python manage.py runserver
, which will listen on port 5000.
按照中的说明设置项目,并在继续进行之前确保测试通过。 完成后,使用python manage.py runserver
运行服务器,它将侦听端口5000。
To test, update LoginComponent
to use the login
and register
methods from the service:
要测试,请更新LoginComponent
以使用服务中的login
和register
方法:
1122334455667788991010111112121313141415151616171718181919202021212222232324242525262627272828292930303131 |
Refresh in the browser and you should see a success in the JavaScript console, after the user is logged in, with the token:
在浏览器中刷新 ,并在用户登录后使用以下令牌在JavaScript控制台中看到成功:
1122334455 |
Update login.component.html:
更新login.component.html:
11223344556677889910101111121213131414151516161717 |
Take note of the form. We used the [(ngModel)]
directive on each of the form inputs to capture those values in the controller. Also, when the form is submitted, the ngSubmit
directive handles the event by firing the onLogin()
method.
注意表格。 我们在每个表单输入上使用了[(ngModel)]
指令,以捕获控制器中的这些值。 另外,提交表单时, ngSubmit
指令通过触发onLogin()
方法来处理事件。
Now, let’s update the component code, adding in onLogin()
:
现在,让我们更新组件代码,添加onLogin()
:
1122334455667788991010111112121313141415151616171718181919202021212222 |
If you have the Angular web server running, you should see the error Cannot find module '../../models/user'
in the browser. Before our code will work, we need to create a User
model.
如果您正在运行Angular Web服务器,则应该在浏览器中看到错误Cannot find module '../../models/user'
。 在我们的代码生效之前,我们需要创建一个User
模型。
11 |
Update src/app/models/user.ts:
更新src / app / models / user.ts:
112233 |
Our User
model has two properties, email
and password
. The ?
character is a special operator that indicates that initializing User
with explicit email
and password
values is optional. This is equivalent to the following class in Python:
我们的User
模型具有两个属性, email
和password
。 ?
字符是一个特殊的运算符,它指示使用显式的email
和password
值初始化User
是可选的。 这等效于Python中的以下类:
11223344 |
Don’t forget to update auth.service.ts to use the new object.
不要忘记更新auth.service.ts以使用新对象。
1122334455667788991010111112121313141415151616171718181919 |
One last thing. We need to import the FormsModule
in the app.module.ts file.
最后一件事。 我们需要导入FormsModule
在app.module.ts文件。
1122334455667788991010111112121313141415151616171718181919202021212222232324242525262627272828 |
So, when the form is submitted, we capture the email and password and pass them to the login()
method on the service.
因此,提交表单后,我们将捕获电子邮件和密码,并将它们传递给服务上的login()
方法。
Test this out with-
用-测试一下
michael@realpython.com
michael
michael@realpython.com
michael
Again, you should see a success in the javaScript console with the token.
同样,您应该在带有令牌的javaScript控制台中看到成功。
Just like for the login functionality, we need to add a component for registering a user. Start by generating a new Register component:
就像登录功能一样,我们需要添加一个组件来注册用户。 首先生成一个新的Register组件:
11 |
Update src/app/components/register/register.component.html
更新src / app / components / register / register.component.html
11223344556677889910101111121213131414151516161717 |
Then, update src/app/components/register/register.component.ts as follows:
然后,如下更新src / app / components / register / register.component.ts:
1122334455667788991010111112121313141415151616171718181919202021212222 |
Add a new route handler to the app.module.ts file:
将新的路由处理程序添加到app.module.ts文件:
11223344 |
Test it out by registering a new user!
通过注册新用户进行测试!
Next, let’s add the token to Local Storage for persistence by replacing the console.log(user.json());
with localStorage.setItem('token', user.data.token);
in src/app/components/login/login.component.ts:
接下来,让我们通过替换console.log(user.json());
将令牌添加到本地存储以实现持久性console.log(user.json());
与localStorage.setItem('token', user.data.token);
在src / app / components / login / login.component.ts中:
112233445566778899 |
Do the same within src/app/components/register/register.component.ts:
在src / app / components / register / register.component.ts中执行相同的操作:
112233445566778899 |
As long as that token is present, the user can be considered logged in. And, when a user needs to make an AJAX request, that token can be used.
只要存在该令牌,就可以认为该用户已登录。并且,当用户需要发出AJAX请求时,可以使用该令牌。
NOTE: Besides the token, you could also add the user id and email to Local Storage. You would just need to update the server-side to send back that info when a user logs in.
注意:除了令牌,您还可以将用户ID和电子邮件添加到本地存储。 您只需要更新服务器端即可在用户登录时发回该信息。
Test this out. Ensure that the token is present in Local Storage after you log in.
测试一下。 登录后,确保令牌在本地存储中存在。
To test out login persistence, we can add a new view that verifies that the user is logged in and that the token is valid.
为了测试登录持久性,我们可以添加一个新视图来验证用户是否已登录以及令牌是否有效。
Add the following method to AuthService
:
将以下方法添加到AuthService
:
1122334455667788 |
Take note of Authorization: 'Bearer ' + token
. This is called a , which is sent along with the request. On the server, we are simply checking for the Authorization
header, and then whether the token is valid. Can you find this code on the server-side?
注意Authorization: 'Bearer ' + token
。 这称为 ,它与请求一起发送。 在服务器上,我们只需检查Authorization
标头,然后检查令牌是否有效。 您可以在服务器端找到此代码吗?
Then, generate a new Status component:
然后,生成一个新的Status组件:
11 |
Create the HTML template, src/app/components/status/status.component.html:
创建HTML模板src / app / components / status / status.component.html:
11223344556677 |
And change the component code in src/app/components/status/status.component.ts:
并在src / app / components / status / status.component.ts中更改组件代码:
112233445566778899101011111212131314141515161617171818191920202121222223232424252526262727 |
Finally, add a new route handler to the app.module.ts file:
最后,将新的路由处理程序添加到app.module.ts文件:
1122334455 |
Ready to test? Log in, and then navigate to . If there is a token in Local Storage, you should see:
准备测试了吗? 登录,然后导航到 。 如果本地存储中有令牌,则应该看到:
11223344 |
Why? Well, if you dig deeper on the server-side, you will find that the token is only valid for 5 seconds in project/server/models.py:
为什么? 好吧,如果您在服务器端进行更深入的研究,您会发现该令牌在project / server / models.py中仅有效5秒钟:
112233445566778899101011111212131314141515161617171818 |
Update this to 1 day:
更新至1天:
11 |
And then test it again. You should now see something like:
然后再次测试。 您现在应该看到类似以下内容:
112233445566778899 |
Finally, let’s redirect to the status page after a user successfully registers or logs in. Update src/app/components/login/login.component.ts like so:
最后,让我们在用户成功注册或登录后重定向到状态页面。像这样更新src / app / components / login / login.component.ts:
112233445566778899101011111212131314141515161617171818191920202121222223232424 |
Then update src/app/components/register/register.component.ts:
然后更新src / app / components / register / register.component.ts:
112233445566778899101011111212131314141515161617171818191920202121222223232424 |
Test it out!
测试一下!
Right now, all routes are open; so, regardless of whether a user is logged in or not, they they can access each route. Certain routes should be restricted if a user is not logged in, while other routes should be restricted if a user is logged in:
现在,所有路线都开放; 因此,无论用户是否登录,他们都可以访问每个路由。 如果用户未登录,则应限制某些路由,而如果用户已登录,则应限制其他路由:
/
– no restrictions/login
– restricted when logged in/register
– restricted when logged in/status
– restricted when not logged in/
–无限制 /login
– /login
受限制 /register
–登录时受限制 /status
–在未登录时受限制 To achieve this, add either EnsureAuthenticated
or LoginRedirect
to each route, depending on whether you want to guide the user to the status
view or the login
view.
为此,请根据您是要引导用户进入status
视图还是login
视图,向每条路由添加EnsureAuthenticated
或LoginRedirect
。
Start by creating two new services:
首先创建两个新服务:
1122 |
Replace the code in the ensure-authenticated.service.ts file as follows:
如下所示,确保代码中的代码替换为sure-authenticated.service.ts:
11223344556677889910101111121213131414151516161717 |
And replace the code in the login-redirect.service.ts like so:
并像下面这样替换login-redirect.service.ts中的代码:
11223344556677889910101111121213131414151516161717 |
Finally, update the app.module.ts file to import and configure the new services:
最后,更新app.module.ts文件以导入和配置新服务:
11223344556677889910101111121213131414151516161717181819192020212122222323242425252626272728282929303031313232333334343535363637373838393940404141424243434444454546464747484849495050515152525353 |
Note how we are adding our services to a new route property, canActivate
. The routing system uses the services in the canActivate
array to determine whether to display the requested URL path. If the route has LoginRedirect
and the user is already logged in, then they will be redirected to the status
view. Including the EnsureAuthenticated
service redirects the user to the login
view if they attempt to access a URL that requires authentication.
注意我们如何将服务添加到新的路由属性canActivate
。 路由系统使用canActivate
数组中的服务来确定是否显示请求的URL路径。 如果路由具有LoginRedirect
并且用户已经登录,则他们将被重定向到status
视图。 如果用户尝试访问需要身份验证的URL,则将其包括在内的EnsureAuthenticated
将用户重定向到login
视图。
Test one last time.
最后一次测试。
In this tutorial, we went through the process of adding authentication to an Angular 4 + Flask app using JSON Web Tokens.
在本教程中,我们介绍了使用JSON Web令牌向Angular 4 + Flask应用程序添加身份验证的过程。
What’s next?
下一步是什么?
Try switching out the Flask back-end for a different web framework, like Django or Bottle, using the following endpoints:
尝试使用以下端点将Flask后端切换到其他Web框架(如Django或Bottle),例如:
/auth/register
/auth/login
/auth/logout
/auth/user
/auth/register
/auth/login
/auth/logout
/auth/user
翻译自:
angular 异步验证
转载地址:http://nvqwd.baihongyu.com/