使用Auth0和Auth0锁在Angular中进行身份验证
身份验证可能很困难,并且每次在应用程序中需要它时重新发明轮子肯定没有乐趣。 值得庆幸的是,不同的服务和工具可以为我们完成繁重的工作。 我们已经讨论过使用 Firebase 实现 身份验证,所以现在让我们探索一个替代方案:Auth0。 Auth0 是一个非常强大的解决方案,它提供了您期望从身份验证提供商那里获得的所有功能(社交登录、电子邮件/密码登录、授权规则……)
在这篇文章中,我们将使用 Auth0 Lock 小部件 ,它允许在您的应用程序中嵌入一个弹出窗口以进行身份验证。 您还可以在 Auth0 的托管登录页面上实现身份验证,在这种情况下,您可能需要 参考本指南 。
这篇文章涵盖了 Angular 2+ 应用程序的身份验证。
设置
首先,您需要创建一个 Auth0 帐户,然后创建一个新的 单页 Web 应用程序 客户端。
创建客户端后,您将能够根据自己的喜好配置设置。 重要的一件事是添加一个回调 URL,该 URL 反映了 Angular 应用程序中的实际登录回调路由。 在这里,我们将创建一个 login 路由,因此我们将添加 http://localhost:4200/login
作为我们唯一允许的回调 URL。 Auth0 将在身份验证后重定向到它。
在您的客户端设置中,您还可以访问 域 和 客户端 ID 信息。 在应用的 environment.ts 文件中添加该信息:
环境.ts
export const environment = { production: false, auth0: { domain: 'your-awesome-domain.auth0.com', clientId: 'XXXXXXXXXXXXXXXXXXXXXXXXXXX', callbackURL: 'http://localhost:4200/login' } };
您的项目中还需要三个额外的包:auth0-js、auth0-lock 和 angular2-jwt。 让我们使用 npm 或 Yarn 将它们安装到我们的项目中:
$ yarn add auth0-js auth0-lock angular2-jwt # or, using npm: $ npm install auth0-js auth0-lock angular2-jwt
现在将 auth0.min.js 添加到应用程序构建中包含的脚本列表中:
.angular-cli.json
..., "scripts": [ "../node_modules/auth0-js/build/auth0.min.js" ], ...
租户
使用 Auth0,您可以创建多个租户以适应不同的部署环境(development、production、staging,...)每个租户都有自己的域名(例如:my-app-dev.auth0.com
和 my-app.auth0.com
)。 这样,您可以为生产创建一个不同的客户端,您只需使用不同的域名、客户端 ID 和回调 URL 填充您的生产环境文件。
组件和路由设置
我们将向我们的应用程序添加两个组件:一个 home 组件和一个 login 回调组件。 我们可以使用 Angular CLI 轻松生成新组件:
$ ng g c home $ ng g c login
接下来,让我们设置一个简单的路由模块:
app.routing.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LoginComponent } from './login/login.component'; import { HomeComponent } from './home/home.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent } ];
认证服务
让我们也使用 Angular CLI 创建一个 Auth 服务:
$ ng g s auth
此时,您需要确保您的路由模块已导入到您的应用程序模块中,并且验证服务也由应用程序模块提供。
让我们开始设置身份验证服务:
auth.service.ts
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { environment } from '../environments/environment'; import { tokenNotExpired } from 'angular2-jwt'; import Auth0Lock from 'auth0-lock'; @Injectable() export class AuthService { auth0Options = { theme: { logo: '/assets/alligator-logo.svg', primaryColor: '#DFA612' }, auth: { redirectUrl: environment.auth0.callbackURL, responseType: 'token id_token', audience: https://${environment.auth0.domain}/userinfo, params: { scope: 'openid profile' } }, autoclose: true, oidcConformant: true, }; lock = new Auth0Lock( environment.auth0.clientId, environment.auth0.domain, this.auth0Options ); constructor(private router: Router) { this.lock.on('authenticated', (authResult: any) => { console.log('Nice, it worked!'); this.router.navigate(['/']); // go to the home route // ...finish implementing authenticated }); this.lock.on('authorization_error', error => { console.log('something went wrong', error); }); } login() { this.lock.show(); } logout() { // ...implement logout }
这里有几点需要注意:
- 我们首先定义一个 Auth0Lock 的新实例,它接受客户端 ID、域和一个配置对象。 有很多 配置选项 可用,在所需选项之上,我们还添加了一些主题选项来设置锁定小部件的样式。
- 在选项中,我们还使用 scopes 键指定我们想要返回的数据类型。 在这里,除了默认的 openid 之外,我们还对获取 profile 信息感兴趣。
- 在服务的构造函数中,我们侦听锁实例上的 authenticated 或 authorization_error 事件。 authenticated 事件的回调将包含我们何时验证成功的逻辑。
- 登录方法与在我们的锁实例上调用 show 方法一样容易实现。
- 我们必须回来完成 logout 和 isAuthenticated 方法的实现。
我们现在可以在我们的 home 组件中注入 auth 服务:
home.component.ts
import { Component } from '@angular/core'; import { AuthService } from '../auth.service'; @Component({ selector: 'app-home', templateUrl: './home.component.html' }) export class HomeComponent {
让我们在模板中添加登录和注销按钮:
home.component.html
<button *ngIf="!auth.isAuthenticated()" (click)="auth.login()"> Sign Up or Login </button> <button *ngIf="auth.isAuthenticated()" (click)="auth.logout()"> Logout </button>
有了我们的基本身份验证服务,Auth0 嵌入已经开始工作,我们可以注册或登录:
配置文件,IsAuthenticated,注销
让我们完成我们的认证服务实现。 对于我们的示例,我们将 Auth0 返回的 JSON Web 令牌保存到本地存储。 然后可以使用对后端 API 的 HTTP 请求的 Bearer 前缀将该令牌添加到 Authorization 标头。 然后,后端将负责确保令牌有效。 我们还将获取我们使用 scopes 请求的帐户配置文件信息并将其保存到本地存储。
一、authenticated事件成功的逻辑:
auth.service.ts(部分)
this.lock.on('authenticated', (authResult: any) => { this.lock.getUserInfo(authResult.accessToken, (error, profile) => { if (error) { throw new Error(error); } localStorage.setItem('token', authResult.idToken); localStorage.setItem('profile', JSON.stringify(profile)); this.router.navigate(['/']);
在这里,我们在锁实例上调用 getUserInfo 并传入从成功认证返回的访问令牌。 getUserInfo 让我们可以访问用户的配置文件信息。
已认证
我们的 isAuthenticated 方法对我们的应用程序了解是否有经过身份验证的用户很有用,并因此调整 UI。
为了实现它,我们将使用 angular2-jwt 的 tokenNotExpired
方法。 如果没有令牌或令牌已过期,它将返回 false:
isAuthenticated() { return tokenNotExpired(); }
登出
由于使用 JWT 进行身份验证是无状态的,因此我们只需从本地存储中删除令牌和配置文件即可注销:
auth.service.ts
logout() { localStorage.removeItem('profile'); localStorage.removeItem('token'); }
🔑 你有它! 为您的应用程序提供简单的身份验证。