赞
踩
原文:https://auth0.com/blog/how-to-configure-create-react-app/#Test-Your-Custom-Script
Auth0 是一个全球领先的 Identity-as-a-Service (IDaaS) 服务商,为数以千计的企业客户提供现代身份认证解决方案。除了经典的 “用户名密码认证过程” 外,Auth0 也允许你增加诸如 “社交媒体登录” 、 “多因子认证”、 “无密码登录” 等等特性,所有这些只需要一些点击就能完成。
用 Auth0 保证 React 应用安全是十分简单方便的。
要完成本文说明的内容,你需要一个 Auth0 账号。如果你还没有,现在是个 注册免费 Auth0 账户(https://auth0.com/signup) 的好时机。
同时,如果你想在一个干净的环境中完成本章节内容,你能通过一条命令轻易创建一个 React 应用:
npx create-react-app react-auth0
然后,进入创建好的 react-auth0
目录,就可以按下面的步骤开发了。
要为你的 React 应用赋予一个 Auth0 账户,你需要创建一个 Auth0 Application。所以,根据 https://manage.auth0.com/#/applications 的描述做如下操作:
点击 Create Application 按钮
为你的新应用定义一个 Name (如 "React Demo")
选择 Single Page Web Applications 作为其类型
点击 Create 按钮完成这个过程
在创建应用之后,Auth0 会将你重定向到其 Quick Start tab 页中。你得点击到 Settings tab 页去设置一些白名单 URL 以供 Auth0 在认证过程后调用。这是一项 Auth0 实现的安全性措施,用以避免敏感数据泄露(如 ID Tokens)。
所以,当你到达 Settings tab 页时,寻找到 Allowed Callback URLs 并在其中增加 http://localhost:3000/callback
。在本教程中,这个简单的 URL 就足够了。
好了!从 Auth0 的视角看,你已经开始很好的保证你的 React 应用的安全了。
要用 Auth0 保证 React 应用安全,只有三项依赖需要安装:
auth0.js
react-router
react-router-dom
要安装这些依赖,到项目根目录下面执行如下的命令:
npm install --save auth0-js react-router react-router-dom
注意: 如果你想要可获得的最佳安全性,应该依照 https://auth0.com/docs/universal-login 上的说明进行。该方法包括了重定向用户到一个托管在 Auth0 网站上的登录页面,该页面通过 你的 Auth0 dashboard (https://manage.auth0.com/) 可以方便快捷地定制化。如果你想要更多学习这种最佳实践,可参阅 https://auth0.com/docs/guides/login/universal-vs-embedded 页面。
安装好这三个库之后,你就可以创建一个服务来处理认证过程了。可以将该服务叫做 Auth
并用如下代码将其创建到 src/Auth/
目录:
- // src/Auth/Auth.js
- import auth0 from 'auth0-js';
-
- export default class Auth {
- constructor() {
- this.auth0 = new auth0.WebAuth({
- // 必须更新以下三行!
- domain: '<AUTH0_DOMAIN>',
- audience: 'https://<AUTH0_DOMAIN>/userinfo',
- clientID: '<AUTH0_CLIENT_ID>',
- redirectUri: 'http://localhost:3000/callback',
- responseType: 'token id_token',
- scope: 'openid profile'
- });
-
- this.getProfile = this.getProfile.bind(this);
- this.handleAuthentication = this.handleAuthentication.bind(this);
- this.isAuthenticated = this.isAuthenticated.bind(this);
- this.login = this.login.bind(this);
- this.logout = this.logout.bind(this);
- this.setSession = this.setSession.bind(this);
- }
-
- getProfile() {
- return this.profile;
- }
-
- handleAuthentication() {
- return new Promise((resolve, reject) => {
- this.auth0.parseHash((err, authResult) => {
- if (err) return reject(err);
- console.log(authResult);
- if (!authResult || !authResult.idToken) {
- return reject(err);
- }
- this.setSession(authResult);
- resolve();
- });
- })
- }
-
- isAuthenticated() {
- return new Date().getTime() < this.expiresAt;
- }
-
- login() {
- this.auth0.authorize();
- }
-
- logout() {
- // 清除 id token 和过期时间
- this.idToken = null;
- this.expiresAt = null;
- }
-
- setSession(authResult) {
- this.idToken = authResult.idToken;
- this.profile = authResult.idTokenPayload;
- // 设置 id token 的过期时间
- this.expiresAt = authResult.expiresIn * 1000 + new Date().getTime();
- }
- }
你刚刚创建的这个 Auth
服务包含了用于处理登入、登出不同步骤的各种函数。下面的列表概述了这些函数:
getProfile
: 返回已登录用户的 profile
handleAuthentication
: 查找 URL hash 中的认证过程结果。然后,该函数用 auth0-js
中的 parseHash
方法处理结果
isAuthenticated
: 检查用户 ID token 是否过期
login
: 初始化登录过程,将用户重定向到登录页面
logout
: 清除用户的 tokens 和过期时间
setSession
: 设置用户的 ID token、profile 及过期时间
除了这些函数,该类还包含了一个名为 auth0
的属性,用来从你的 Auth0 应用中提取初始化值。同时记住你 必须 替换掉其中的 <AUTH0_DOMAIN>
和 <AUTH0_CLIENT_ID>
占位符是重要的。
注意: 对于
<AUTH0_DOMAIN>
占位符,你得将它替换成类似your-subdomain.auth0.com
的形式,其中your-subdomain
是你在创建 Auth0 账户(或你的 Auth0 租户名, https://auth0.com/docs/getting-started/create-tenant)时选择的子域名。而对于<AUTH0_CLIENT_ID>
,需要将其替换为从你之前创建的 Auth0 应用中 Client ID 域中拷贝的随机字符串。
由于使用了 Auth0 登录页面,用户会被带离你的应用。不过,在其认证过后,又会被自动带回到你之前设置过的回调 URL 上 (也就是 http://localhost:3000/callback
)。这意味着你需要创建一个组件来负责这个路由。
所以,创建 src/Callback
目录并在其中创建一个叫做 Callback.js
的文件,插入如下的代码:
- // src/Callback/Callback.js
- import React from 'react';
- import { withRouter } from 'react-router';
-
- function Callback(props) {
- props.auth.handleAuthentication().then(() => {
- props.history.push('/');
- });
-
- return (
- <div>
- Loading user profile.
- </div>
- );
- }
-
- export default withRouter(Callback);
这个组件,正如你所见,负责触发 handleAuthentication
过程,并在该过程结束时将用户带入主页。而当该组件处理认证结果的过程中,只是简单的显示了 “loading the user profile” 。
当 Auth
和 Callback
组件都创建完毕,就可以重构 App
组件以整合所有事情了:
- // src/App.js
-
- import React from 'react';
- import {withRouter} from 'react-router';
- import {Route} from 'react-router-dom';
- import Callback from './Callback/Callback';
- import './App.css';
-
- function HomePage(props) {
- const {authenticated} = props;
-
- const logout = () => {
- props.auth.logout();
- props.history.push('/');
- };
-
- if (authenticated) {
- const {name} = props.auth.getProfile();
- return (
- <div>
- <h1>Howdy! Glad to see you back, {name}.</h1>
- <button onClick={logout}>Log out</button>
- </div>
- );
- }
-
- return (
- <div>
- <h1>I don't know you. Please, log in.</h1>
- <button onClick={props.auth.login}>Log in</button>
- </div>
- );
- }
- function App(props) {
- const authenticated = props.auth.isAuthenticated();
- return (
- <div className="App">
- <Route exact path='/callback' render={() => (
- <Callback auth={props.auth}/>
- )}/>
- <Route exact path='/' render={() => (
- <HomePage
- authenticated={authenticated}
- auth={props.auth}
- history={props.history}
- />)
- }/>
- </div>
- );
- }
- export default withRouter(App);
在本例中,实际上你在一个文件中定义了两个组件(就是为了简单)。首先定义一个 HomePage
组件展示已登录用户名的信息,以及告知未登录用户去登录的信息。同时,文件中的 App
组件负责决定根据路由哪些子组件必须渲染。
要注意你在所有组件中(App
、HomePage
和 Callback
)都用到了 Auth
服务。因此你需要这个服务的一个全局实例,并且将其包含在 App
组件中。
所以,要创建这个全局 Auth
实例并整合到应用中,需要更新 index.js
文件:
- // src/index.js
-
- import React from 'react';
- import ReactDOM from 'react-dom';
- import { BrowserRouter } from 'react-router-dom';
- import Auth from './Auth/Auth';
- import './index.css';
- import App from './App';
-
- const auth = new Auth();
-
- ReactDOM.render(
- <BrowserRouter>
- <App auth={auth} />
- </BrowserRouter>,
- document.getElementById('root')
- );
这样就完成了!你已经用 Auth0 保护了你的 React 应用。如果用 npm start
启动了应用,你将能够借助 Auth0 的帮助自己实现认证了,也能看到 React 应用显示了你的名字(如果你的身份提供者确实提供了一个名字的话)。
如果你想学习更多的话,Auth0 官方文档中也提供了各种前端框架的整合方法:
查看更多前端好文
请搜索 fewelife 关注公众号
转载请注明出处
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。