[译] 用 Auth0 保证 React 应用安全

原文:auth0.com/blog/how-to…css

Auth0

Auth0 是一个全球领先的 Identity-as-a-Service (IDaaS) 服务商,为数以千计的企业客户提供现代身份认证解决方案。除了经典的 “用户名密码认证过程” 外,Auth0 也容许你增长诸如 “社交媒体登陆”“多因子认证”“无密码登陆” 等等特性,全部这些只须要一些点击就能完成。前端

用 Auth0 保证 React 应用安全是十分简单方便的。react

要完成本文说明的内容,你须要一个 Auth0 帐号。若是你尚未,如今是个 注册免费 Auth0 帐户 (auth0.com/signup) 的好时机。npm

同时,若是你想在一个干净的环境中完成本章节内容,你能经过一条命令轻易建立一个 React 应用:安全

npx create-react-app react-auth0
复制代码

而后,进入建立好的 react-auth0 目录,就能够按下面的步骤开发了。bash

设立一个 Auth0 应用

要为你的 React 应用赋予一个 Auth0 帐户,你须要建立一个 Auth0 Application。因此,根据 manage.auth0.com/#/applicati… 的描述作以下操做:前端框架

  1. 点击 Create Application 按钮
  2. 为你的新应用定义一个 Name (如 "React Demo")
  3. 选择 Single Page Web Applications 做为其类型
  4. 点击 Create 按钮完成这个过程

在建立应用以后,Auth0 会将你重定向到其 Quick Start tab 页中。你得点击到 Settings tab 页去设置一些白名单 URL 以供 Auth0 在认证过程后调用。这是一项 Auth0 实现的安全性措施,用以免敏感数据泄露(如 ID Tokens)。react-router

因此,当你到达 Settings tab 页时,寻找到 Allowed Callback URLs 并在其中增长 http://localhost:3000/callback。在本教程中,这个简单的 URL 就足够了。app

好了!从 Auth0 的视角看,你已经开始很好的保证你的 React 应用的安全了。框架

依赖和设置

要用 Auth0 保证 React 应用安全,只有三项依赖须要安装:

  • auth0.js
  • react-router
  • react-router-dom

要安装这些依赖,到项目根目录下面执行以下的命令:

npm install --save auth0-js react-router react-router-dom
复制代码

注意: 若是你想要可得到的最佳安全性,应该依照 auth0.com/docs/univer… 上的说明进行。该方法包括了重定向用户到一个托管在 Auth0 网站上的登陆页面,该页面经过 你的 Auth0 dashboard (manage.auth0.com/) 能够方便快捷地定制化。若是你想要更多学习这种最佳实践,可参阅 auth0.com/docs/guides… 页面。

安装好这三个库以后,你就能够建立一个服务来处理认证过程了。能够将该服务叫作 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 租户名, auth0.com/docs/gettin…)时选择的子域名。而对于 <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”

AuthCallback 组件都建立完毕,就能够重构 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 组件负责决定根据路由哪些子组件必须渲染。

要注意你在全部组件中(AppHomePageCallback)都用到了 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 官方文档中也提供了各类前端框架的整合方法:

https://auth0.com/docs/quickstart/spa

扩展阅读



--End--

查看更多前端好文
请搜索 fewelife 关注公众号

转载请注明出处

相关文章
相关标签/搜索