gatsby_如何使用Gatsby和Netlify构建经过身份验证的无服务器JAMstack应用程序

gatsby

When interacting with a backend, a JAMstack app can do everything a mobile app can do, without the tyranny of the app store. This is a fundamental insight that goes as deep as the fight for a more open, secure, decoupled, faster web.

与后端交互时,JAMstack应用程序可以执行移动应用程序可以执行的所有操作,而无需应用程序商店的暴政。 这是一个基本见解,它与争取更开放,安全,分离,更快的网络的斗争一样深入。

Static site generators (SSGs) are traditionally used to generate markup HTML for static sites, and even e-commerce sites, but the modern generation of JavaScript SSGs are enabling full-blown, blazing fast web apps. Gatsby uses JavaScript to rehydrate Markup into a fully dynamic React app - which means you can use APIs to do all sorts of dynamic functionality!

传统上,静态网站生成器(SSG)用于为静态网站,甚至是电子商务网站生成标记HTML,但是现代JavaScript SSG可以实现功能完善,功能强大的快速Web应用程序。 Gatsby使用JavaScript将Markup补水为一个完全动态的React应用程序-这意味着您可以使用API​​来执行各种动态功能!

Let's see how we can incrementally add functionality to a Gatsby static site with Netlify Functions, and then add authentication with Netlify Identity to create a proper Gatsby app. We'll gradually build up to a full working demo with:

让我们看看如何使用Netlify Functions向Gatsby静态站点增量添加功能,然后使用Netlify Identity添加身份验证以创建适当的Gatsby应用程序。 我们将逐步构建一个完整的演示示例

  • 👋🏼Dynamic Clientside Pages in Gatsby

    Ga盖茨比中的动态客户端页面
  • 🚋Serverless Functions (with Netlify Dev)

    🚋无服务器功能(使用Netlify Dev)
  • 🕵🏼‍♂️Hide API Secrets from being exposed to Frontend

    API‍from️HideAPI Secrets暴露于前端
  • 🔏Authentication (with Netlify Identity)

    🔏身份验证(使用Netlify身份)
  • 🏠Protected Routes

    🏠保护路线
  • 🔐Authenticated Serverless Functions (why not!)

    less经过认证的无服务器功能(为什么不!)
  • 😻External Provider login with GitHub, Bitbucket, Google, etc.

    with使用GitHub,Bitbucket,Google等进行外部提供商登录

不是您父母的静态网站生成器 (Not Your Parent's Static Site Generator)

Why would you use something like Gatsby over Jekyll or Hugo or one of the hundreds of Static Site Generators out there? There are many reasons, but one of the unique selling points is how Gatsby helps you build "Static Progressive Web Apps" with React.

为什么要在Jekyll或Hugo上使用Gatsby之类的东西,还是在那里使用数百个静态站点生成器之一? 原因有很多 ,但独特的卖点之一是Gatsby如何帮助您使用React构建“静态渐进式Web应用程序”

Gatsby's ability to rehydrate (what a delicious word!) the DOM means you can do incredibly dynamic things with JavaScript and React that would be much harder with legacy SSG's.

Gatsby能够补充 DOM的水分 (真是个好话!),这意味着您可以使用JavaScript和React进行难以置信的动态处理,而这对于传统SSG而言则要困难得多。

Let's say you have a typical static Gatsby site, like gatsby-starter-default. You can npm run build it, and it spits out a bunch of HTML files. Great! I can host that for free!

假设您有一个典型的静态Gatsby网站,例如gatsby-starter-default 。 您可以npm run build它,它会吐出一堆HTML文件。 大! 我可以免费托管!

Now imagine your client comes to you and asks you to add some custom logic that needs to be executed on the server:

现在,假设您的客户端来找您,并要求您添加一些需要在服务器上执行的自定义逻辑:

Oh no! Now you have to rewrite everything and move to a Digital Ocean droplet!

不好了! 现在,您必须重写所有内容,然后移至数字海洋滴!

I'm kidding. No, you don't have to rewrite everything.

我在开玩笑。 不,您不必重写所有内容。

The beauty of serverless functions is that it is incrementally adoptable - your site grows with your needs - and with JavaScript you can rerender entire sections of your site based on live API data. Of course, the more you do this, the more resource intensive (in terms of bandwidth and computation) it can be, so there is a performance tradeoff. Your site should be as dynamic as you need it to be, but no more. Gatsby is perfect for this.

无服务器功能的优点在于它可以逐步采用- 您的网站随您的需求增长 -借助JavaScript,您可以根据实时API数据重新呈现网站的整个部分。 当然,您做得越多,资源消耗(就带宽和计算而言)就越多,因此需要权衡性能。 您的网站应具有所需的动态性,但仅此而已。 盖茨比对此很完美。

使用Netlify Dev添加无服务器功能 (Using Netlify Dev to add Serverless Functions)

Netlify Functions are a great low configuration solution for adding serverless functionality to your Gatsby site.

Netlify Functions是一种出色的低配置解决方案,用于向您的Gatsby站点添加无服务器功能。

We'll assume you have a Gatsby site ready to go already, preferably linked to a Git remote like GitHub. If you don't have one, fork and download gatsby-starter-default. Let's walk through the steps to add Netlify Functions:

我们假设您已经可以使用Gatsby网站,最好将其链接到GitHub之类的Git远程站点。 如果您没有,请分叉并下载gatsby-starter-default 。 让我们逐步介绍添加Netlify函数的步骤:

  1. Install Netlify CLI and login:

    安装Netlify CLI并登录

npm i -g netlify-cli
netlify login # to link your free Netlify account

Pretty straightforward.

非常简单。

  1. Create your Netlify instance for your Gatsby site:

    为您的Gatsby网站创建Netlify实例

netlify init

You will be prompted for a "build command", which for Gatsby is yarn build, and a "publish directory", which for Gatsby is public. You can also save this in a netlify.toml config file, or the CLI will create it for you:

系统将提示您输入“ build command”(对于Gatsby是yarn build )和“发布目录”(对于Gatsby是public 。 您也可以将其保存在netlify.toml配置文件中 ,否则CLI将为您创建它:

[build]
  command = "yarn build"
  functions = "functions"
  publish = "public"

As you can see in the above example, We'll also specify where we'll save our functions to the creatively named functions folder.

如您在上面的示例中看到的,我们还将指定将函数保存到创造性命名的functions文件夹中的位置。

  1. Create your first Netlify Function: Netlify CLI has a set of templates available to help you get started writing serverless functions. Just run:

    创建您的第一个Netlify功能 :Netlify CLI具有一组模板,可帮助您开始编写无服务器功能。 赶紧跑:

netlify functions:create # ntl functions:create also works

You'll be presented with an autocomplete list. We'll pick the token-hider example for now. Once you select it, the CLI will copy out the necessary files, and install the necessary axios dependencies.

系统会为您显示自动完成列表。 我们现在将选择token-hider示例。 选择后,CLI将复制必要的文件,并安装必要的axios依赖项。

Notice that token-hider.js includes this line:

注意token-hider.js包含以下行:

const { API_SECRET = "shiba" } = process.env

This is meant to simulate API secrets that you don't want to expose to the frontend. You can set these as build environment variables on your site's Netlify Dashboard. You can name them whatever you like, and for the purposes of our demo we've provided a default, but of course feel free to modify this code however you like. It's Just JavaScript™!

这是为了模拟您不想公开给前端的API机密。 您可以在站点的Netlify仪表板上将它们设置为构建环境变量 。 您可以随意命名,为演示目的,我们提供了默认值,但是您可以随意修改此代码。 就是JavaScript™!

  1. Make sure function dependencies are installed with netlify-lambda (Optional but Recommended)

    确保通过netlify-lambda安装了功能依赖netlify-lambda (可选,但推荐)

Notice that your function comes with its own package.json and node_modules. This means each function can have their own independently managed dependencies, but you also need to make sure these dependencies are installed when you deploy or when someone else clones your repo. You can either check them into git (ugh!), or write a bash script to do this installation. But don't worry, there's a simple utility to automate this:

注意,您的函数带有其自己的package.jsonnode_modules 。 这意味着每个功能可以具有自己独立管理的依赖关系,但是您还需要确保在部署或其他人克隆存储库时已安装这些依赖关系。 您可以将它们检入git(ugh!),或编写bash脚本进行此安装。 但是不用担心,有一个简单的实用程序可以自动执行此操作:

yarn add -D netlify-lambda

And add a postinstall script in package.json (this isn't Netlify specific, it is part of how npm works):

并在package.json添加一个postinstall脚本(这不是Netlify特有的,它是npm的一部分):

"scripts": {
    "postinstall": "netlify-lambda install"
  },
  1. Fire up Gatsby and Functions with Netlify Dev

    使用Netlify Dev启动Gatsby和功能

Netlify Dev is the local proxy server embedded in the CLI that we will use to develop our Functions alongside our Gatsby app. You can start it like so:

Netlify Dev是嵌入在CLI中的本地代理服务器,我们将使用它与Gatsby应用程序一起开发功能。 您可以这样启动:

netlify dev # or ntl dev

Your Gatsby app will now be accessible at http://localhost:8888 and your function will be accessible at http://localhost:8888/.netlify/function/token-hider. Check it out in your browser!

现在可以在http://localhost:8888上访问您的Gatsby应用程序,并且可以从http://localhost:8888/.netlify/function/token-hider上访问您的函数。 在浏览器中查看!

How are both the Gatsby dev server and the Netlify Functions server both available on the same local port? How come the API_SECRET you set on the Netlify side is available in local development? The rough mental image you should have looks something like this:

Gatsby开发服务器和Netlify Functions服务器在同一个本地端口上如何都可用? 您在Netlify端设置的API_SECRET如何在本地开发中可用? 您应该具有的粗略心理印象如下所示

ASCCII-ART

You can hit your Netlify Function from anywhere in your Gatsby app! For example, in any event handler or lifecycle method, insert:

您可以从Gatsby应用程序中的任何位置访问Netlify功能! 例如,在任何事件处理程序或生命周期方法中,插入:

fetch("/.netlify/functions/token-hider")
  .then(response => response.json())
  .then(console.log)

and watch a list of dog images pop up in your console. If you are new to React, I highly recommend reading through the React docs to understand where and how to insert event handlers so you can, for example, respond to a button click.

并查看控制台中弹出的狗图像列表。 如果您不熟悉React,我强烈建议您阅读React文档,以了解在何处以及如何插入事件处理程序,例如,您可以响应按钮单击

添加身份验证 (Adding Authentication)

So, yes, your site can now be more dynamic than any static site: It can hit any database or API. You can hide API tokens from prying eyes. It runs rings around CORS (by the way, you can also use Netlify Redirects for that). But its not an app app. Yet!

因此,是的,您的站点现在可以比任何静态站点更具动态性:它可以访问任何数据库或API。 您可以从窥视中隐藏API令牌。 它围绕CORS运行(顺便说一句,您也可以为此使用Netlify重定向 )。 但它不是应用程序。 然而!

The key thing about web apps (and, let's face it, the key thing users really pay for) is they all have some concept of user, and that brings with it all manner of complication from security to state management to role-based access control. Entire routes need to be guarded by authentication, and sensitive content shielded from Gatsby's static generation. Sometimes there are things you -don't- want Google's spiders to see!

Web应用程序的关键点(让我们面对现实,这是用户真正付钱的关键点)是它们都具有user概念,并且带来了从安全到状态管理再到基于角色的访问控制的所有复杂方式。 整个路由都需要通过身份验证来保护,并且敏感内容应免受Gatsby的静态生成的影响。 有时有些事情-您不希望Google的蜘蛛看到!

It's a different tier of concern, which makes it hard to write about in the same article as a typical Gatsby tutorial. But we're here to make apps, so let's bring it on!

这是一个不同的关注点,这使得与典型的Gatsby教程在同一篇文章中很难撰写。 但是我们在这里制作应用程序,所以让我们继续吧!

将Netlify身份和经过身份验证的页面添加到Gatsby (Adding Netlify Identity and Authenticated Pages to Gatsby)

  1. Enable Netlify Identity: Netlify Identity doesn't come enabled by default. You'll have to head to your site admin (eg https://app.netlify.com/sites/YOUR_AWESOME_SITE/identity) to turn it on. Read the docs for further info on what you can do, for example add Facebook or Google social sign-on!

    启用Netlify身份 :默认情况下不启用Netlify身份 。 您必须前往站点管理员(例如https://app.netlify.com/sites/YOUR_AWESOME_SITE/identity )才能将其打开。 阅读文档以获取有关您可以做什么的更多信息,例如添加Facebook或Google社交登录!

  2. Install dependencies: npm install gatsby-plugin-netlify-identity react-netlify-identity-widget @reach/dialog @reach/tabs @reach/visually-hidden gatsby-plugin-create-client-paths

    安装依存关系npm install gatsby-plugin-netlify-identity react-netlify-identity-widget @reach/dialog @reach/tabs @reach/visually-hidden gatsby-plugin-create-client-paths

  3. Configure Gatsby: for dynamic-ness!

    配置Gatsby :动态!

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-create-client-paths`,
      options: { prefixes: [`/app/*`] },
    },
    {
      resolve: `gatsby-plugin-netlify-identity`,
      options: {
        url: "https://YOUR_AWESOME_SITE_INSTANCE_HERE.netlify.com",
      },
    },
  ],
}

This sets up everything under the /app route to be dynamic on the clientside, which means you can put it behind an authentication wall.

这会将/app路由下的所有内容都设置为在客户端是动态的,这意味着您可以将其置于身份验证墙后面。

  1. Add the login widget: netlify-identity-widget is a framework-agnostic overlay that ships with a nice signup/login UI. However it is a 60kb package, so there is a 6kb alternative that simply assumes you're using React: react-netlify-identity-widget.

    添加登录小部件netlify-identity-widget是一个与框架无关的覆盖,带有不错的注册/登录UI。 但是,它是一个60kb的软件包,因此有一个6kb的替代方案,仅假设您使用React: react-netlify-identity-widget

The widget is implemented as an accessible modal with @reach/dialog, so you need to put it somewhere in your app:

该小部件通过@reach/dialog实现为可访问的模式,因此您需要将其放在应用程序中的某个位置:

// src/app/login.js
import React from "react"
import { navigate } from "gatsby"

import { IdentityModal } from "react-netlify-identity-widget"
import "react-netlify-identity-widget/styles.css" // delete if you want to bring your own CSS

export default function Login() {
  const [dialog, setDialog] = React.useState(false)
  return (
    <div>
      <h1>Log in</h1>
      <button onClick={() => setDialog(true)}>log in</button>
      <IdentityModal
        showDialog={dialog}
        onCloseDialog={() => setDialog(false)}
        onLogin={user => navigate("/app/profile")}
        onSignup={user => navigate("/app/profile")}
      />
    </div>
  )
}

react-netlify-identity-widget uses React Context, so it normally requires adding a Provider, but gatsby-plugin-netlify-identity already did that for you (that's its whole purpose!).

react-netlify-identity-widget使用React Context,因此通常需要添加Provider,但是gatsby-plugin-netlify-identity已经为您做到了(这就是它的全部目的!)。

As you might expect, you can use that Context in the rest of your app. react-netlify-identity-widget exports a Custom Consumer Hook called useIdentityContext, which helps do some runtime checks and makes TypeScript typing easier by removing an undefined check.

如您所料,您可以在应用程序的其余部分中使用该上下文。 react-netlify-identity-widget导出一个名为useIdentityContext自定义使用者钩子 ,该钩子有助于执行一些运行时检查,并通过删除undefined检查使TypeScript键入更加容易。

useIdentityContext returns an identity object, and you can see the plethora of data and methods it exposes to you on the docs. Let's use them to implement a NavBar component!

useIdentityContext返回一个identity对象, 您可以在docs上看到它向您提供的大量数据和方法 。 让我们用它们来实现NavBar组件!

// src/app/components/NavBar.js
import React from "react"
import { Link, navigate } from "gatsby"
import { useIdentityContext } from "react-netlify-identity-widget"

export default function NavBar() {
  const { user, isLoggedIn, logoutUser } = useIdentityContext()
  let message = isLoggedIn
    ? `Hello, ${user.user_metadata && user.user_metadata.full_name}`
    : "You are not logged in"
  const handleClick = async event => {
    event.preventDefault()
    await logoutUser()
    navigate(`/app/login`)
  }
  return (
    <div>
      <span>{message}</span>
      <nav>
        <span>Navigate the app: </span>
        <Link to="/app/">Main</Link>
        <Link to="/app/profile">Profile</Link>
        {isLoggedIn ? (<a href="/" onClick={handleClick}>Logout</a>) : (<Link to="/app/login">Login</Link>)}
      </nav>
    </div>
  )
}
  1. Write the rest of your app: Because of our configuration in gatsby-plugin-create-client-paths, any sub paths in src/pages/app will be exempt from Gatsby static generation. To keep the dividing line between app and site crystal clear, I like to have all my dynamic Gatsby code in a dedicated app folder. This means you can use @reach/router with react-netlify-identity-widget to write a standard dynamic React app with private, authenticated routes. Here's some sample code to give you an idea of how to hook them up:

    编写其余的应用程序 :由于我们在gatsby-plugin-create-client-paths进行了配置, gatsby-plugin-create-client-paths src/pages/app任何子路径都将不受Gatsby静态生成的影响。 为了使应用程序和网站之间的界限清晰明了,我希望将所有动态Gatsby代码放在专用的app文件夹中。 这意味着您可以将@reach/routerreact-netlify-identity-widget以编写具有私有,经过身份验证的路由的标准动态React应用。 以下是一些示例代码,可让您了解如何进行连接:

// src/app/app.js
import React from "react"
import { Router } from "@reach/router"
import Layout from "../components/layout"
import NavBar from "./components/NavBar"
import Profile from "./profile"
import Main from "./main"
import Login from "./login"
import { useIdentityContext } from "react-netlify-identity-widget"
import { navigate } from "gatsby"

function PrivateRoute(props) {
  const { isLoggedIn } = useIdentityContext()
  const { component: Component, location, ...rest } = props

  React.useEffect(
    () => {
      if (!isLoggedIn && location.pathname !== `/app/login`) {
        // If the user is not logged in, redirect to the login page.
        navigate(`/app/login`)
      }
    },
    [isLoggedIn, location]
  )
  return isLoggedIn ? <Component {...rest} /> : null
}
function PublicRoute(props) {
  return <div>{props.children}</div>
}

export default function App() {
  return (
    <Layout>
      <NavBar />
      <Router>
        <PrivateRoute path="/app/profile" component={Profile} />
        <PublicRoute path="/app">
          <PrivateRoute path="/" component={Main} />
          <Login path="/login" />
        </PublicRoute>
      </Router>
    </Layout>
  )
}

Phew that was a lot! but you should have a solid starting point for your app now :)

ew! 但是您现在应该为您的应用确定一个坚实的起点:)

奖励积分:经过身份验证的Netlify功能🤯 (Bonus points: Authenticated Netlify Functions 🤯)

Just like every magic act has a pledge, a turn, and a prestige, I have one last tidbit for you. Nothing on the client-side is safe. Although you can send along Netlify Identity user ID's to your Netlify Function endpoints for authenticated access from your Gatsby App (for example in the body of a POST request), you'll never be truly sure if that flow is secure either from malicious users or snooping.

就像每一个魔术表演都有誓言,转身和声望一样 ,我还有最后一个小窍门。 客户端上没有什么是安全的 。 尽管您可以将Netlify身份用户ID发送到Netlify功能端点,以便通过Gatsby App进行经过身份验证的访问(例如在POST请求的正文中),但是您永远无法真正确定该流是否对恶意用户安全或安全。偷窥。

The best way to do authenticated actions inside serverless functions is to do it from inside the context of the function itself. Fortunately, Netlify Identity and Functions work seamlessly together. All you have to do is to send along the user's JWT when hitting your endpoint:

做认证的动作内无服务器的功能,最好的办法是从功能本身的上下文做到这一点。 幸运的是, Netlify身份和功能可以无缝地协同工作 。 您要做的就是在碰到端点时发送用户的JWT

// in your gatsby app
const { user } = useIdentityContext()
// in an event handler
fetch("/.netlify/functions/auth-hello", {
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
    Authorization: "Bearer " + user.token.access_token, // like this
  },
}).then(/* etc */)

If even this is too much boilerplate, you can even use the fetch wrapper that ships with the identity object:

如果甚至太多了,您甚至可以使用identity对象随附的fetch包装器:

// in your gatsby app
const { authedFetch } = useIdentityContext()
// in an event handler
authedFetch("/.netlify/functions/auth-hello").then(/* etc */)

And then inside your Netlify function, you can now check the user object or pass it on to your end API or database:

然后在Netlify函数中,您现在可以检查user对象或将其传递给最终的API或数据库:

module.exports = { handler }
async function handler(event, context) {
  if (context.clientContext) {
    const { user } = context.clientContext
    // you can get actual user metadata you can use!
    return {
      statusCode: 200,
      body: JSON.stringify({
        msg: "super secret info only available to authenticated users",
        user,
      })
    }
  } else {
    return {
      statusCode: 401,
      body: JSON.stringify({
        msg:
          "Error: No authentication detected! Note that netlify-lambda doesn't locally emulate Netlify Identity.",
      }),
    }
  }
}

Gatsby + Netlify-非常适合您的下一次黑客马拉松 (Gatsby + Netlify - Perfect for your next Hackathon)

As you can see, it's a few steps to turn your static Gatsby sites into dynamic, authenticated, fully serverless apps with Netlify's free tools. This makes Gatsby a perfect tool for your next app. If you're at a hackathon, short on time, or just like to see a full working demo, check any of the following links.

如您所见,使用Netlify的免费工具将您的静态Gatsby网站变成动态的,经过身份验证的,完全无服务器的应用程序只需几个步骤。 这使盖茨比成为下一个应用程序的理想工具。 如果您正在参加黑客马拉松,时间紧缺,或者只是想观看完整的演示,请查看以下任何链接。

翻译自: https://www.freecodecamp.org/news/building-jamstack-apps/

gatsby

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值