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:
主要依赖项:
Angular v4.2.4 (via Angular CLI v1.3.2)Flask v0.12Python v3.6.2 Angular v 4.2.4 (通过Angular CLI v 1.3.2 ) 烧瓶v 0.12 Python v 3.6.2
验证工作流程 (Auth Workflow)
Here’s the full user auth process:
这是完整的用户身份验证过程:
Client logs in and the credentials are sent to the serverIf the credentials are correct, the server generates a token and sends it as a response to the clientClient receives and stores the token in Local StorageClient then sends token to server on subsequent requests within the request header 客户端登录并将凭据发送到服务器 如果凭据正确,则服务器将生成令牌并将其作为响应发送给客户端 客户端接收令牌并将其存储在本地存储中 然后,客户端在请求标头中的后续请求上向服务器发送令牌
项目设置 (Project Setup)
Start by globally installing the Angular CLI:
首先全局安装Angular CLI :
Then generate a new Angular 4 project boilerplate:
然后生成一个新的Angular 4项目样板:
Fire up the app after the dependencies install:
安装依赖项后启动应用程序:
It will probably take a minute or two to compile and build your application. Once done, navigate to http://localhost:4200 to ensure the app is up and running.
编译和构建应用程序可能需要一两分钟。 完成后,导航到http:// localhost:4200以确保该应用程序已启动并正在运行。
Open up the project in your favorite code editor, and then glance over the code:
在您喜欢的代码编辑器中打开项目,然后浏览一下代码:
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 theAppModule
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 Angular Style Guide, since the app generated from the CLI follows the recommended structure from that guide, as well as the Angular4Crud Tutorial.
注意:刚开始使用Angular 4? 查看Angular Style Guide ,因为从CLI生成的应用程序遵循该指南的推荐结构,以及Angular4Crud教程 。
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存储库并更新远程:
Now, let’s wire up a new component…
现在,让我们连接一个新组件 ……
验证组件 (Auth Component)
First, use the CLI to generate a new Login component:
首先,使用CLI生成一个新的Login组件:
This set up the component files and folders and even wired it up to app.module.ts. Next, let’s change the ponent.ts file to the following:
这将设置组件文件和文件夹,甚至将其连接到app.module.ts。 接下来,让我们将ponent.ts文件更改为以下内容:
If you haven’t used TypeScript 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 ,那么这段代码对您来说可能看起来很陌生。 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 importComponent
from the@angular/core
package. TheLoginComponent
class is the component’s controller, and we use theexport
operator to make it available for other classes to import.
在Angular 4中,我们通过使用@Component
装饰器包装配置对象来定义组件。 我们可以通过导入所需的类在程序包之间共享代码。 在这种情况下,我们从@angular/core
包中导入Component
。LoginComponent
类是组件的控制器,我们使用export
运算符使其可用于其他类的导入。
Add the following HTML to the ponent.html:
将以下HTML添加到ponent.html中:
Next, configure the routes, via the RouterModule in the app.module.ts file:
接下来,配置路由,通过RouterModule在app.module.ts文件:
Finish enabling routing by replacing all HTML in the ponent.html file with the<router-outlet>
tag:
通过使用<router-outlet>
标记替换ponent.html文件中的所有HTML,完成启用路由:
Runng serve
in your terminal, if you haven’t already, and then navigate to http://localhost:4200/login. If all went well you should see thejust a test
text.
如果尚未在终端中运行ng serve
,请导航至http:// localhost:4200 / login 。 如果一切顺利,您应该just a test
看到just a test
文本。
引导样式 (Bootstrap Style)
To quickly add some style, update the index.html, adding in Bootstrap and wrapping the<app-root></app-root>
in a container:
要快速添加某种样式,请更新index.html,添加Bootstrap并将<app-root></app-root>
包装在容器中 :
You should see the app auto reload as soon as you save.
保存后,您应该会看到该应用程序自动重新加载。
验证服务 (Auth Service)
Next, let’s create a global service to handle a user logging in, logging out, and signing up:
接下来,让我们创建一个全局服务来处理用户登录,注销和注册:
Edit the auth.service.ts so that it has the following code:
编辑auth.service.ts,使其具有以下代码:
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
装饰器进行定义。
完整性检查 (Sanity Check)
Before adding anything significant toAuthService
, let’s make sure the service itself is wired up correctly. To do that, within ponent.ts inject the service and call thetest()
method:
在向AuthService
添加重要内容之前,请确保服务本身已正确连接。 为此,在ponent.ts中注入服务并调用test()
方法:
We’ve introduced some new concepts and keywords. Theconstructor()
function is a special method that we use to set up a new instance of a class. Theconstructor()
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 theprivate
keyword. Passing aprivate
variable in the constructor is a shortcut to defining it within the class and then assigning the argument’s value to it. Notice how theauth
variable is accessible to thethis
object after it is passed into the constructor.
我们介绍了一些新概念和关键字。constructor()
函数是一种特殊的方法,我们使用它来建立类的新实例。constructor()
是我们传递类所需的任何参数的地方,包括我们要注入的任何提供程序(即AuthService
)。 在TypeScript中,我们可以使用private
关键字隐藏外界的变量。 在构造函数中传递private
变量是在类中定义它,然后为其分配参数值的快捷方式。 请注意,在this
对象传递到构造函数之后,auth
变量如何可访问this
对象。
We implement theOnInit
interface to ensure that we explicitly define angOnInit()
function. ImplementingOnInit
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 theAuthService
in app.module.ts and add it to theproviders
:
与自动添加的组件不同,必须在@NgModule
上手动导入和配置@NgModule
。 因此,要使其正常工作,您还必须在AuthService
中导入AuthService并将其添加到providers
:
Run the server and then navigate to http://localhost:4200/login. You should seeworking
logged to the JavaScript console.
运行服务器,然后导航到http:// localhost:4200 / login 。 您应该看到将working
记录到JavaScript控制台。
用户登录 (User Login)
To handle logging a user in, update theAuthService
like so:
要处理用户登录,AuthService
像这样更新AuthService
:
We employ the help of some built-in Angular classes,Headers
andHttp
, to handle our AJAX calls to the server.
我们利用一些内置的Angular类Headers
和Http
的帮助来处理对服务器的AJAX调用。
Also, update the app.module.ts file to import theHttpModule
.
另外,更新app.module.ts文件以导入HttpModule
。
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
组件。
用户注册 (User Registration)
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 theregister
method:
让我们继续并添加注册用户的功能,这类似于登录用户。更新src / app / services / auth.service.ts,注意register
方法:
Now, to test this we need to set up a back end…
现在,要对此进行测试,我们需要设置一个后端…
服务器端设置 (Server-side Setup)
For the server-side, we’ll use the finished project from a previous blog post, Token-Based Authentication With Flask. You can view the code from the flask-jwt-auth repository.
对于服务器端,我们将使用先前博客文章Flask的基于令牌的身份验证中完成的项目。 您可以从flask-jwt-auth存储库中查看代码。
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:
在新的终端窗口中克隆项目结构:
Follow the directions in the README to set up the project, making sure the tests pass before moving on. Once done, run the server withpython manage.py runserver
, which will listen on port 5000.
按照自述文件中的说明设置项目,并在继续进行之前确保测试通过。 完成后,使用python manage.py runserver
运行服务器,它将侦听端口5000。
完整性检查 (Sanity Check)
To test, updateLoginComponent
to use thelogin
andregister
methods from the service:
要测试,请更新LoginComponent
以使用服务中的login
和register
方法:
Refresh http://localhost:4200/login in the browser and you should see a success in the JavaScript console, after the user is logged in, with the token:
在浏览器中刷新http:// localhost:4200 / login ,并在用户登录后使用以下令牌在JavaScript控制台中看到成功:
验证登录 (Auth Login)
Update ponent.html:
更新ponent.html:
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, thengSubmit
directive handles the event by firing theonLogin()
method.
注意表格。 我们在每个表单输入上使用了[(ngModel)]
指令,以捕获控制器中的这些值。 另外,提交表单时,ngSubmit
指令通过触发onLogin()
方法来处理事件。
Now, let’s update the component code, adding inonLogin()
:
现在,让我们更新组件代码,添加onLogin()
:
If you have the Angular web server running, you should see the errorCannot find module '../../models/user'
in the browser. Before our code will work, we need to create aUser
model.
如果您正在运行Angular Web服务器,则应该在浏览器中看到错误Cannot find module '../../models/user'
。 在我们的代码生效之前,我们需要创建一个User
模型。
Update src/app/models/user.ts:
更新src / app / models / user.ts:
OurUser
model has two properties,email
andpassword
. The?
character is a special operator that indicates that initializingUser
with explicitemail
andpassword
values is optional. This is equivalent to the following class in Python:
我们的User
模型具有两个属性,email
和password
。?
字符是一个特殊的运算符,它指示使用显式的email
和password
值初始化User
是可选的。 这等效于Python中的以下类:
Don’t forget to update auth.service.ts to use the new object.
不要忘记更新auth.service.ts以使用新对象。
One last thing. We need to import theFormsModule
in the app.module.ts file.
最后一件事。 我们需要导入FormsModule
在app.module.ts文件。
So, when the form is submitted, we capture the email and password and pass them to thelogin()
method on the service.
因此,提交表单后,我们将捕获电子邮件和密码,并将它们传递给服务上的login()
方法。
Test this out with-
用-测试一下
email:michael@
password:michael
电子邮件:michael@
密码:michael
Again, you should see a success in the javaScript console with the token.
同样,您应该在带有令牌的javaScript控制台中看到成功。
认证注册 (Auth Register)
Just like for the login functionality, we need to add a component for registering a user. Start by generating a new Register component:
就像登录功能一样,我们需要添加一个组件来注册用户。 首先生成一个新的Register组件:
Update src/app/components/register/ponent.html
更新src / app / components / register / ponent.html
Then, update src/app/components/register/ponent.ts as follows:
然后,如下更新src / app / components / register / ponent.ts:
Add a new route handler to the app.module.ts file:
将新的路由处理程序添加到app.module.ts文件:
Test it out by registering a new user!
通过注册新用户进行测试!
本地存储 (Local Storage)
Next, let’s add the token to Local Storage for persistence by replacing theconsole.log(user.json());
withlocalStorage.setItem('token', user.data.token);
in src/app/components/login/ponent.ts:
接下来,让我们通过替换console.log(user.json());
将令牌添加到本地存储以实现持久性console.log(user.json());
与localStorage.setItem('token', user.data.token);
在src / app / components / login / ponent.ts中:
Do the same within src/app/components/register/ponent.ts:
在src / app / components / register / ponent.ts中执行相同的操作:
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.
测试一下。 登录后,确保令牌在本地存储中存在。
用户状态 (User Status)
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 toAuthService
:
将以下方法添加到AuthService
:
Take note ofAuthorization: 'Bearer ' + token
. This is called a Bearer schema, which is sent along with the request. On the server, we are simply checking for theAuthorization
header, and then whether the token is valid. Can you find this code on the server-side?
注意Authorization: 'Bearer ' + token
。 这称为Bearer模式 ,它与请求一起发送。 在服务器上,我们只需检查Authorization
标头,然后检查令牌是否有效。 您可以在服务器端找到此代码吗?
Then, generate a new Status component:
然后,生成一个新的Status组件:
Create the HTML template, src/app/components/status/ponent.html:
创建HTML模板src / app / components / status / ponent.html:
And change the component code in src/app/components/status/ponent.ts:
并在src / app / components / status / ponent.ts中更改组件代码:
Finally, add a new route handler to the app.module.ts file:
最后,将新的路由处理程序添加到app.module.ts文件:
Ready to test? Log in, and then navigate to http://localhost:4200/status. If there is a token in Local Storage, you should see:
准备测试了吗? 登录,然后导航到http:// localhost:4200 / status 。 如果本地存储中有令牌,则应该看到:
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秒钟:
Update this to 1 day:
更新至1天:
And then test it again. You should now see something like:
然后再次测试。 您现在应该看到类似以下内容:
Finally, let’s redirect to the status page after a user successfully registers or logs in. Update src/app/components/login/ponent.ts like so:
最后,让我们在用户成功注册或登录后重定向到状态页面。像这样更新src / app / components / login / ponent.ts:
Then update src/app/components/register/ponent.ts:
然后更新src / app / components / register / ponent.ts:
Test it out!
测试一下!
路线限制 (Route Restriction)
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 eitherEnsureAuthenticated
orLoginRedirect
to each route, depending on whether you want to guide the user to thestatus
view or thelogin
view.
为此,请根据您是要引导用户进入status
视图还是login
视图,向每条路由添加EnsureAuthenticated
或LoginRedirect
。
Start by creating two new services:
首先创建两个新服务:
Replace the code in the ensure-authenticated.service.ts file as follows:
如下所示,确保代码中的代码替换为sure-authenticated.service.ts:
And replace the code in the login-redirect.service.ts like so:
并像下面这样替换login-redirect.service.ts中的代码:
Finally, update the app.module.ts file to import and configure the new services:
最后,更新app.module.ts文件以导入和配置新服务:
Note how we are adding our services to a new route property,canActivate
. The routing system uses the services in thecanActivate
array to determine whether to display the requested URL path. If the route hasLoginRedirect
and the user is already logged in, then they will be redirected to thestatus
view. Including theEnsureAuthenticated
service redirects the user to thelogin
view if they attempt to access a URL that requires authentication.
注意我们如何将服务添加到新的路由属性canActivate
。 路由系统使用canActivate
数组中的服务来确定是否显示请求的URL路径。 如果路由具有LoginRedirect
并且用户已经登录,则他们将被重定向到status
视图。 如果用户尝试访问需要身份验证的URL,则将其包括在内的EnsureAuthenticated
将用户重定向到login
视图。
Test one last time.
最后一次测试。
下一步是什么? (What’s Next?)
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
翻译自: //08/user-authentication-with-angular-4-and-flask/
angular 异步验证