auth0 和okta
本文最初发布在Okta开发者博客上 。 感谢您支持使SitePoint成为可能的合作伙伴。
渐进式Web应用程序 (PWA)是Web开发平台上的最新技术,它们及时出现是为了解决一个日益严重的问题。 当发布新功能时,许多公司都在努力使组织中孤立的开发团队保持最新。 一些公司甚至试图确定开发Web应用程序和移动应用程序的成本是否值得。 毫不奇怪,这是大多数公司希望避免的头痛问题。 PWA可以为公司提供移动应用程序所需的许多功能,而无需管理多个团队和代码库。
PWA在快速连接时表现出色,而在脱机或Wi-Fi上运行时仍然表现良好,而Wi-Fi的速度还不够快,无法称为Wi-Fi(有时称为“ Lie-Fi”)。 它通过缓存和JavaScript“服务工作者”来做到这一点,该服务者拦截服务器调用并尝试首先从缓存中提供数据,然后在服务器最终响应时,它将用服务器中可能的“刷新”数据替换缓存的数据。
最近, Ionic团队发布了一个名为Stencil的新项目。 Stencil是一个生成符合标准的Web组件的编译器。 与大多数JavaScript框架不同,它不会向浏览器交付代码的“框架”。 它仅使用您编写的代码,并使用其编译器来创建普通组件。 您还可以将Stencil的编译器与您喜欢的框架一起使用。 Stencil入门项目是使用Stencil的最简单方法,它可以生成一个基本应用程序,该应用程序在Lighthouse的渐进式Web应用程序记分卡上的得分接近100%。
要开始使用Stencil构建PWA,请克隆启动程序应用程序并将其与GitHub远程服务器分离。
警告 :模板尚未发布1.0版本(截至撰写本文时)。 因此请注意,如果继续,您将处于早期采用者的领域。 如果发现错误,请提交问题 。
设置入门应用程序
git clone https://github.com/ionic-team/stencil-starter.git first-stencil
cd first-stencil
git remote rm origin
然后,安装新的Stencil应用程序将需要的所有依赖项。
npm install
您可能会在fsevents
周围的node-pre-gyp
fsevents
看到一些警告。 这里什么也看不到。 这只是为了解决一个讨厌的小npm错误 。
接下来,将Okta Auth SDK(通过CDN)添加到index.html
页面的底部, index.html
在</body>
标记之前。
<script src="https://ok1static.oktacdn.com/assets/js/sdk/okta-auth-js/1.8.0/okta-auth-js.min.js" type="text/javascript"></script>
虽然有Okta的Auth SDK的npm软件包,但Stencil很难编译它。 总体而言,如果您仅使用CDN来包括它,那么它现在效果更好。
如果您像我一样,接下来要做的就是运行npm start
并使用Lighthouse检查该站点。 如果这样做,您会注意到分数有点低。 特别是,它不会注册服务工作者,也不会在离线时返回200。 那是因为它是开发构建,通常,您不希望服务工作者在开发中拦截服务器调用并返回缓存的数据。
为了确保您可以准确地描绘出使用Stencil开箱即用的PWA类型,请确保使用npm run build
运行生产 npm run build
。 完成后,您将看到一个www
文件夹,并且在该文件夹内,您将看到一个sw.js
文件。 那是您的服务人员!
设置您的Okta应用程序
如果您尚未这样做,请创建一个永久性的开发者帐户 。
注册后,单击顶部菜单中的“ 应用程序 ”。 然后单击“ 添加应用程序” 。
然后,您将进入应用程序创建向导。 选择“ 单页应用程序” ,然后单击底部的“ 下一步 ”。
在下一个屏幕上,您将看到单页应用程序模板提供的默认设置。 将应用程序的名称更改为更具描述性的名称,例如“ Stencil SPA”。 另外,将基本URI和登录重定向URI设置更改为使用端口3333,因为这是应用程序将在其中运行的地方。 其余的默认设置都可以。
![](https://img-blog.csdnimg.cn/2022010614335768252.png)
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
点击底部的完成 。
从列表中选择新创建的应用程序,然后单击“ 常规”选项卡以查看常规设置。
在底部,您会看到一个Client ID设置(很明显,您不会感到困惑)。 复制它以在您的Stencil应用程序中使用。 您还将需要您的Okta组织URL,您可以在仪表板页面的右上角找到该URL。 它可能看起来像“ https://dev-XXXXXX.oktapreview.com”。
添加身份验证组件
在components
文件夹中,添加一个名为app-auth
的新文件夹。 这是您的登录页面组件所在的位置。 您可以随心所欲地调用它,我只是遵循此处的入门应用程序设置的命名约定。 我绝对建议您尽早决定命名惯例并坚持使用。
在新创建的app-auth
文件夹中,创建两个文件: app-auth.css
和app-auth.tsx
。 首先创建app-auth.tsx
文件的外壳。
import { Component } from '@stencil/core';
@Component({
tag: 'app-auth',
styleUrl: 'app-auth.css'
})
export class AppAuth {
render() {
return <div>Hello</div>;
}
}
如果像我一样,您可能会想:“这是什么样的科学怪人框架?”
您会在AppAuth
类声明(如Angular)上看到@Component
装饰器,然后在底部像React一样看到render()
方法。 对我来说,这就是模具的美。 它吸收了两个流行框架的一些最佳部分,并使用它们来编译可重用的组件!
添加登录表格
接下来,将JSX(我说对了)添加到新组件中。 将render()
方法更改为:
render() {
return (
<form class="app-auth">
<div class="form-item">
<label>
Username:
<input type="text" name="username" autocomplete="username" />
</label>
</div>
<div class="form-item">
<label>
Password:
<input
type="password"
name="password"
autocomplete="current-password"
/>
</label>
</div>
<div class="form-actions">
<button type="button" onClick={() => this.login()}>
Login
</button>
</div>
</form>
);
}
这只是一个普通的JSX表单,但是登录按钮的onClick
事件目前已连接到不存在的功能。
添加登录方法的依赖项
在创建该函数之前,您需要设置OktaAuth
JavaScript对象以调用Okta API进行身份验证。 您将对象添加到组件的状态,因此在类声明的正下方添加以下行:
@State() authClient: any;
您还必须导入@State()
装饰器。 这用于与组件内部状态有关的值。 在第一个import
语句中,将State添加到解构列表中。
import { Component, State } from '@stencil/core'
您还需要从表单本身获取用户名和密码值,因此像刚刚创建的那样,在@State()
下方的代码中添加@Element()
,其内容如下:
@State() authClient: any;
@Element() host: HTMLElement;
然后还将@Element()
装饰器添加到导入中,使其显示为:
import { Component, State, Element } from '@stencil/core';
login()
函数需要做的最后一件事是访问路由器,因此,如果用户的身份验证成功,则可以将用户重定向到其配置文件页面。 您将需要一个class属性,因此请将其添加到@Element
正下方。
@State() authClient: any;
@Element() host: HTMLElement;
@Prop() history: RouterHistory;
要导入它,请将@Prop()
装饰器添加到@Prop()
入中,然后从核心导入语句下方的@stencil/router
导入RouterHistory
。 @Prop
装饰器用于定义可以传递到组件中的属性。 在这种情况下,它不是传递的值,但是如果需要的话也可以。 最后的导入部分应显示为:
import { Component, Prop, State, Element, Listen } from '@stencil/core';
import { RouterHistory } from '@stencil/router';
最后,要使用从CDN引入的OktaAuth
JavaScript库,请在import语句下方为其添加一个声明。
declare const OktaAuth: any;
添加登录方法
现在,您包括了获得登录功能以通过Okta组织对用户进行身份验证所需的一切。 首先,在AppAuth
类的构造函数中设置OktaAuth
对象。 在RouterHistory
对象的属性下面,添加:
constructor() {
this.authClient = new OktaAuth({
clientId: '{yourClientId}',
url: 'https://{yourOktaDomain}.com',
issuer: 'default'
});
}
您可以从Okta应用程序的常规设置页面获取客户端ID。
您还需要Okta仪表板页面右上角的Okta组织URL。
现在,一切都已为login()
函数设置好了,因此接下来将创建它。 在render()
方法上方,添加一个login()
函数。
login() {
let inputs = this.host.querySelectorAll('input');
let user = {
username: inputs[0].value,
password: inputs[1].value
};
return this.authClient.signIn(user)
.then(res => {
if (res.status === 'SUCCESS') {
return this.authClient.token
.getWithoutPrompt({
responseType: 'id_token',
scopes: ['openid', 'profile', 'email'],
sessionToken: res.sessionToken,
redirectUri: 'http://localhost:3333'
})
.then(token => {
localStorage.setItem(
'okta_id_token',
JSON.stringify(token)
);
this.history.push('/profile', {});
});
} else {
throw `Unable to handle ${res.status} status code`;
}
})
.fail(function(err) {
console.error(err);
});
}
由于确实是组件的“实质”,所以我将带您逐步了解这里发生的情况。
首先,将所有输入都放入组件的form
元素内。 然后,使用用户名和密码从其各自的输入中创建用户对象。
接下来, authClient
对象用于与创建的用户对象一起调用signIn()
方法。 它返回一个Promise,因此您可以通过获取响应来处理then
条件,并检查响应的状态是否为200。如果是,则调用authClient.token
的getWithoutPrompt()
方法,该方法也将返回getWithoutPrompt()
。 它需要一个responseType
属性,该属性设置为id_token
,因为这就是您想从Okta获得的。 您还要求提供三个范围,这些范围将为您提供与新认证的用户相关联的openid,个人资料和电子邮件数据。 该方法需要从signIn()
方法的响应返回的会话令牌。 最后,您已告诉该函数回调redirectUri
,该URL在创建应用程序时被设置为Okta中的受信任重定向源。
在此承诺的then
条件下,您将接收到的id令牌设置为okta_id_token
在本地存储中。 如果一切正常,则将用户重定向到个人资料页面。
如果响应的状态不是200,则只会抛出一个错误,表明它无法处理其他任何状态。 最后, signIn()
方法调用的失败条件只是将所有错误记录到控制台。
简化登录
在此过程中,有两件事会使该组件变得更好一点:能够按Enter键登录而不用单击“登录”按钮;如果该人尝试进入登录页面,甚至不显示登录表单。他们已经登录时。
为此,请添加一种方法,以将用户直接登录到个人资料页面(如果已登录)。与React组件一样,Stencil组件也具有生命周期方法。 取而代之的componentWillMount()
的React,模板有一个componentWillLoad()
方法,所以这是什么,你会在这里使用。
componentWillLoad() {
let idToken = localStorage.getItem('okta_id_token');
if (idToken) {
this.history.push('/profile', {});
}
}
简而言之,您要做的就是从本地存储中读取令牌。 如果存在,则假定它们已登录并将其重定向到个人资料页面。
使此登录表单更易于使用的最后一件事是添加使用Enter键提交表单的功能。 Stencil具有一些内置的按键监听器。 在这种情况下,请使用“ keydown.enter”侦听器。 在导入Component
的最顶层import语句中导入@Listen()
装饰器。
import { Component, Prop, State, Element, Listen } from '@stencil/core';
然后在componentWillLoad()
函数下方添加一个'keydown.enter'事件的处理程序。
@Listen('keydown.enter')
handleEnter() {
this.login();
}
更新配置文件页面
现在您已经拥有了一个不错的登录页面,请更新个人资料页面,以便在用户登录后显示用户的声明。
首先,您需要输入用户声明的类型。因此,在app-profile
文件夹中创建一个名为AppUser.tsx
的新文件。 内容很简单,但是很长。 我只是查看了存储在localStorage
中的令牌中的所有声明,并创建了与其匹配的接口。 因此, AppUser.tsx
文件如下:
interface AppUser {
sub: string;
name: string;
locale: string;
email: string;
ver: number;
iss: string;
aud: string;
iat: number;
exp: number;
jti: string;
amr: string[];
idp: string;
nonce: string;
nickname: string;
preferred_username: string;
given_name: string;
family_name: string;
zoneinfo: string;
updated_at: number;
email_verified: boolean;
auth_time: number;
}
在为您的配置文件的用户对象声明类型后,更新app-profile.tsx
文件。
顶部的导入应如下所示:
import { Component, Prop, State } from '@stencil/core';
import { RouterHistory } from '@stencil/router';
删除@Prop()
行以进行match
并替换为:
@Prop() history: RouterHistory;
@State() user: AppUser;
@Prop({ context: 'isServer' }) private isServer: boolean;
isServer
属性是一个特殊属性。 由于Stencil支持预渲染,并且在预渲染期间localStorage
可能不可用,因此您需要将localStorage
调用包装在if(!isServer){}
,以确保它将为生产而构建。 这不应阻止它正常工作,而只是构建过程中的一个解决方法。
对于componentWillLoad()
方法,只需从本地存储中的“ okta_id_token”中读取用户信息:
componentWillLoad() {
if (!this.isServer) {
let token = JSON.parse(localStorage.getItem('okta_id_token'));
if (token) {
this.user = token.claims;
} else {
this.history.push('/login', {});
}
}
}
这也是个人资料页面的保护者,它只是检查令牌是否存在。 如果是这样,它将从中加载索赔。 如果不是,它将重定向到登录页面。
对于render()
方法,对其进行更改以在列表中显示声明。
render() {
if (this.user) {
let keys = Object.keys(this.user);
return <div class="app-profile">
<h2>User Claims</h2>
<ul>
{keys.map(key => <li><span>{key}</span>: {this.user[key]}</li>)}
</ul>
<button onClick={this.logout}>
Logout
</button>
</div>;
}
}
剩下的唯一事情就是添加logout()
方法。 这只会从本地存储中删除令牌并重新加载页面,这将迫使componentWillLoad()
将用户重定向到登录页面。
logout() {
if (!this.isServer) {
localStorage.removeItem('okta_id_token');
location.reload();
}
}
设置登录路径
剩下的唯一事情就是将通往登录组件的路由添加到应用程序中,以便用户可以到达那里。
在components/my-app/my-app.tsx
文件中,在stencil-router
组件内部添加路由,以便最后一部分如下所示:
<stencil-router>
<stencil-route url="/" component="app-home" exact={true} />
<stencil-route url="/profile" component="app-profile" />
<stencil-route url="/login" component="app-auth" />
</stencil-router>
您还需要更新主页上链接的路由。 在components/app-home/app-home.tsx
将stencil-route-link
元素的url更新为不再传递url参数。
<stencil-route-link url="/profile">
<button>
Profile page
</button>
</stencil-route-link>
而已! 现在,您应该能够运行该应用程序,单击个人资料页面,重定向到登录页面,并在登录后重定向回个人资料页面。个人资料页面应显示您的所有声明。已验证。
恭喜,您现在已经拥有一个带有身份验证的PWA,随时可以征服世界!
添加样式
作为额外的奖励,您可能需要在登录表单和个人资料页面中添加一些样式。 以下是我在app-auth.css
登录页面的样式表:
.app-auth {
width: 30%;
margin: 2rem auto;
}
.app-auth .form-item {
padding: .25rem;
}
.app-auth label {
width: 100%;
font-size: 1rem;
color: #999;
}
.app-auth label input {
width: 97%;
border-radius: .25rem;
font-size: 1.5rem;
}
.app-auth .form-actions {
text-align: right;
}
最后,在app-profile.css
仅提供一些简单的样式来加粗每个项目的标签。
.app-profile {
padding: 10px;
}
.app-profile ul li span {
font-weight: bold;
}
现在,当您运行该应用程序时,您将看到一个样式精美的应用程序,可随时用于网络!
学到更多
要了解有关PWA的更多信息,请在Okta开发人员博客上查看Matt Raible的PWA终极指南 。
如果您想了解有关Ionic应用程序的更多信息,请查看Matt的有关构建Ionic应用程序的博客文章。
您可以从Brandon Parise的帖子中了解有关使用VueJS构建基本的CRUD应用程序的信息 。
最后,在这里您可以看到如何使用Node和React设置用户注册 !
与往常一样,如果您有任何问题,可以在下面发表评论或在Twitter @leebrandt上打我,并且不要忘记关注@OktaDev,以获取我们社区的精彩内容以及有关Okta开发人员平台的所有新闻!
翻译自: https://www.sitepoint.com/how-to-add-auth-to-your-pwa-with-okta-and-stencil/
auth0 和okta