10分钟快速实现安全的React + Docker

假如你已经构建了一个 React 应用,但是现在需要部署它。应该怎么做?首先,最好选择一个云提供商,因为它们一般成本低而且部署容易。

大多数云提供商都提供了一种部署静态站点的方法。用 React 构建应用只是 JavaScript、HTML 和 CSS。它们是静态文件,几乎可以在任何 Web 服务器上使用。但实际上,如果你使用了 JSX(JS 中的 HTML)和样式化组件,那么这些可以说只有 JavaScript

Docker 是用于构建和共享容器化应用的事实标准。你可以使用它打包你的应用程序,并包含多种开源 Web 服务器来为你的应用程序提供服务。另外,你还可以通过配置网络服务器来发送安全标头,这样使你的程序更安全。

前提条件:

  • Node 12+
  • Docker
  • Okta 开发者帐户

创建 React 应用

为了集中精力,我用了一位同事已经构建的程序。首先克隆存储库。

git clone https://github.com/oktadeveloper/okta-react-styled-components-example.git react-docker
cd react-docker
npm install

这是一个使用样式化组件的 React 应用,并由 OpenID Connect(aka OIDC)保护。你可以在使用样式化组件构建 React 应用 一文中了解其创建方式。

登录你的 Okta 开发者帐户(你已经创建了一个,对吗?)注册此应用并启用 OIDC 身份验证。

  1. 转到顶部菜单中的 Applications
  2. 选择 Add Application > Single-Page App ,然后单击 Next
  3. 在设置屏幕上,为你的应用命名,例如 React Docker
  4. 确保端口设置为 3000,并且 Login redirect URIhttp://localhost:3000/callback
  5. 点击 Done

出现的界面将为你提供一个客户端 ID。

1.png

将客户端 ID 复制并粘贴到应用程序的 src/App.js 中。 <yourIssuerURI> 的值可以在 Okta 仪表板的 API > Authorization Servers 下找到。例如我的是 https://dev-133320.okta.com/oauth2/default

function App() {
  return (
    <Router>
      <Security issuer='<yourIssuerURI>'
                clientId='<yourClientId>'
                redirectUri={window.location.origin + '/callback'}
                pkce={true}>
        <SecureRoute path='/' exact={true} component={Calendar}/>
        <Route path='/callback' component={LoginCallback}/>
      </Security>
    </Router>
  );
}

<> 括号只是占位符,请确保将其删除!

npm start 启动你的应用。你将被重定向到 Okta 进行身份验证,然后返你的应用。如果你没有重定向,那是因为你已经登录。请在 private 窗口中重试来查看登录过程。

你会看到一个简单、干净的日历,并选择了今天的日期。

2.png

我承认这是一个非常简单的应用,但我们会用它来演示如何用 Docker 进行容器化。

为什么要使用Docker?

你可能会问:“为什么要用 Docker?这不会使事情复杂化吗?”

是的我同意。用 Docker 进行操作比用 Heroku 进行 firebase deploygit push 处理更为复杂。但是如果你真的要使事情复杂化,并用 Kubernetes 去管理你的应用,那么它可以给你更多的控制权。

创建Dockerfile和Nginx配置

在你的根目录中创建一个 Dockerfile

FROM node:14.1-alpine AS builder

WORKDIR /opt/web
COPY package.json package-lock.json ./
RUN npm install

ENV PATH="./node_modules/.bin:$PATH"

COPY . ./
RUN npm run build

FROM nginx:1.17-alpine
RUN apk --no-cache add curl
RUN curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst && \
    chmod +x envsubst && \
    mv envsubst /usr/local/bin
COPY ./nginx.config /etc/nginx/nginx.template
CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
COPY --from=builder /opt/web/build /usr/share/nginx/html

这将会构建你的项目并把 Nginx 添加为 Web服务器。它还将安装 envsubst 版本,该版本允许你用环境变量去替换变量,并设置默认值。

在同一目录中创建一个 nginx.config

server {
    listen       ${PORT:-80};
    server_name  _;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $$uri /index.html;
    }
}

这个文件把 Nginx 配置为将你的 React 应用作为 SPA(其中所有路由都转到 index.html)并在 80 端口上运行。在 uri 前面有两个 $$,以防止 $uri 被替换为空白值。

用 React 应用构建 Docker 镜像

先执行 docker ps 确保你的 Docker 守护进程正在运行。然后运行以下命令来构建你的 Docker 镜像。 命令中的 react-docker 可以是你想要为镜像命名的任何名字。

docker build -t react-docker .

该过程完成后,你将会看到以下消息的内容:

Successfully built 3211a1255527
Successfully tagged react-docker:latest

运行你的 Docker + React 应用

现在,你可以用 docker run 命令通过 Docker 在端口 3000 上运行 React 应用。

docker run -p 3000:80 react-docker

如果你发现这些 docker 命令很难记住,也可以在 package.json文件中添加几个脚本 。

"docker": "docker build -t react-docker .","react-docker": "docker run -p 3000:80 react-docker"

然后就可以用 npm run dockernpm run react-docker 运行了。

很漂亮吧?在短短几分钟内就把你的 React 应用做了 docker 化。

把将你的 React App 部署到 Heroku

你的应用要直到正式投入生产时才会真正的存在,所以让我们把它部署到 Heroku。首先我将向你展示怎样不用 Docker 做到这一点。

首先,你需要 一个 Heroku 帐户。然后,安装 Heroku CLI

打开终端,登录你的 Heroku 帐户,然后创建一个新应用。

heroku login
heroku create

现在,你应该有了一个新的 heroku Git 远程存储库。可以用 git remote -v 来确认。

在带有安全标头的根目录中创建一个 static.json 文件,并把所有 HTTP 请求重定向到 HTTPS。

{
  "headers": {
    "/**": {
      "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;",
      "Referrer-Policy": "no-referrer, strict-origin-when-cross-origin",
      "Strict-Transport-Security": "max-age=63072000; includeSubDomains",
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "DENY",
      "X-XSS-Protection": "1; mode=block",
      "Feature-Policy": "accelerometer 'none'; camera 'none'; microphone 'none'"
    }
  },
  "https_only": true,
  "root": "build/",
  "routes": {
    "/**": "index.html"
  }
}

要读取 “static.json”,你必须用 Heroku static buildpack

把你的更改提交到 Git,添加 Node.js + static buildpack,然后部署 React 应用。

git commit -am "Configure secure headers and static buildpacks"heroku buildpacks:set heroku/nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git
git push heroku master

该过程完成后,使用以下方法在浏览器中打开你的应用程序:

heroku open

你将会被重定向到 Okta,可能会看到以下错误:

The 'redirect_uri' parameter must be an absolute URI that is whitelisted in the client app settings.

要解决这个问题,需要修改 Okta 应用,以将你的 Heroku URL 添加为“登录重定向 URI”。例如https://gentle-peak-37809.herokuapp.com/callback

现在,你应该可以登录并看到你的应用在 Heroku 上运行了!你可以在 https://securityheaders.com 上验证其安全标头是否正确。

3.png

在这个部署示例中,buildpacks 为你完成了所有工作。但是并非每个云提供商都提供 buildpack。这就是需要 Docker 的地方。

把 Docker + React App 部署到 Heroku

当涉及到 Docker 镜像时,Heroku 具有一些出色的功能。如果你的项目有一个 Dockerfile,则可以用 Heroku Container Registry直接部署你的应用。

首先,登录到Container Registry。

heroku container:login

然后,创建一个新的应用。

heroku create

把 Git URL 作为新的 remote 添加到你的应用。

git remote add docker https://git.heroku.com/<your-app-name>.git

然后,把将你的 Docker 镜像 push 到 Heroku 的 Container Registry。

heroku container:push web --remote docker

该过程完成后,release 你的应用程序镜像:

heroku container:release web --remote docker

然后,在浏览器中打开该应用:

heroku open --remote docker

你需要先在 Okta 中添加应用的 URI,然后才能登录。

改善 Docker 中 Nginx 的安全标头

如果在 securityheaders.com 上的 Docker 站点中测试新的 Nginx,你的得分应该是 F

为了解决这个问题,修改你的 nginx.config 添加安全头。

server {
    listen       ${PORT:-80};
    server_name  _;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $$uri /index.html;
    }

    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;";
    add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";
    add_header Feature-Policy "accelerometer 'none'; camera 'none'; microphone 'none'";
}

更新文件后,运行以下命令:

heroku container:push web --remote docker
heroku container:release web --remote docker

现在你应该得到 A

4.png

用 Cloud Native Buildpacks 创建你的 React + Docker 镜像

在本文中,我们学习了把 React 应用部署到 Heroku 的两种方法。首先是利用 buildpack 和 git push。第二个是使用 Heroku 的 Container Registry 和 heroku container:push + heroku push:release

Cloud Native Buildpacks 是 Pivotal 和 Heroku 在 2018 年初发起的一项举措。它具有 pack CLI,可让你用 buildpacks 构建 Docker 映像。

我的好朋友 Joe Kutner是 Heroku 的一名软件架构师,在实现 Cloud Native Buildpacks 中发挥了重要的作用。 Joe 是 JHipster 项目的积极提交者,其作者 The Healthy Programmer 是 Cloud Native Buildpacks 核心团队的创始成员 。他对 Docker 的建议是:“如果不需要,请不要使用 Dockerfile”。

Joe 对我在弄清楚如何使用 buildpacks 创建 Docker 映像的技术上提供了很大的帮助,所以下面的说明应该归功于他。

首先,请 installpack。如果你使用的是 Mac 或 Linux,可以使用 Homebrew。如果用的是 Windows,可以安装其可执行文件

brew tap buildpack/tap
brew install pack

在前面的 buildpacks 示例中,我用了 Heroku 的 Node.js 和静态 buildpacks。

Heroku 静态构建包不是 “Cloud Native” 构建包。它使用旧的(原生云)API。这意味着它与开箱即用的 pack 不兼容。

幸运的是,Heroku 确实提供了 cnb-shim,你可以用它来使其工作。在用 cnb-shim 转换后,Joe 为 Heroku 的静态 buildpack 创建了一个 URL (https://cnb-shim.herokuapp.com/v1/heroku-community/static) 。

在本地构建和运行 Docker 镜像之前,必须先进行一项更改。 从 static.json 中删除 "https_only":true 这一行。

然后用以下命令通过 Node.js 和静态 buildpack(也就是你在 Heroku 上使用的相同 buildpack)构建 Docker 镜像。

pack build react-pack --builder heroku/buildpacks --buildpack \
  heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static

提示:如果你想摆脱 --builder 参数,可以用 pack set-default-builder heroku/buildpacks

该过程完成后,你应该可以运行它。

docker run --rm -it --init -p 3000:3000 --env PORT=3000 okta

如果你发现这些 pack 命令很难被记住,那么可以把它们添加到 package.json 中。

"pack": "pack build react-pack --builder heroku/buildpacks --buildpack heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static","react-pack": "docker run --rm -it --init -p 3000:3000 --env PORT=3000 react-pack"

然后可以使用 npm run packnpm run react-pack 来运行它们。

把将你的 React + Docker 镜像部署到 Docker Hub

通过把它们部署到 Docker Hub 等注册表中,可以轻松共享 Docker 容器。如果你还没有 Docker Hub 帐户,那就先创建一个

拥有帐户之后,登录并 push 你的镜像。在下面的示例中,我正在使用 react-docker,但你也可以使用 react-pack 来部署 buildpacks 版本。

docker login
docker image tag react-docker <your-username>/react-docker
docker push <your-username>/react-docker

默认情况下,这会将其标记为 latest。如果要标记和推送特定版本,可以用:

docker image tag react-docker <your-username>/react-docker:1.0
docker push <your-username>/react-docker

然后其他人就可以用以下命令 pull 并运行:

docker run -p 3000:80 <your-username>/react-docker

把 React + Docker 镜像部署到 Heroku

要把现有映像部署到 Heroku,可以用 docker push。你必须用以下命名约定来标记和推送镜像。

docker tag <image> registry.heroku.com/<app>/<process-type>
docker push registry.heroku.com/<app>/<process-type>

要部署 react-pack 镜像,你可以执行以下操作:

docker tag react-pack registry.heroku.com/fierce-eyrie-08414/web
docker push registry.heroku.com/fierce-eyrie-08414/web
heroku container:release web --remote docker

我尝试了一下,发现没有强制使用 HTTPS。必须将 "https_only":true 添加到 static.json 中,然后重新push。

了解有关 React 和 Docker 的更多信息

在本教程中,我们学习了如何用 Docker 容器化你的 React 应用。你可以用 docker build 手动进行这项操作,也可以用 Heroku 的 Container Registry 通过 Dockerfile 推送和发布项目。在构建容器时,还可以用 pack 命令来利用 Cloud-Native + Heroku 构建包。

如果你用的是 Heroku,它的 buildpack 比 Docker 更容易使用。通过简单的 git push,你可以在 Heroku 的服务器上部署代码并构建。

可以在 GitHub上 的 oktadeveloper/okta-react-docker-example 上找到本示例的源代码。

原文:https://scotch.io/tutorials/react-docker-with-security-in-10-minutes

作者:Matt Raible

更多web前端开发知识,请查阅 HTML中文网 !!

以上就是10分钟快速实现安全的React + Docker的详细内容,更多请关注web前端其它相关文章!

赞(0) 打赏
未经允许不得转载:web前端首页 » JavaScript 教程

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

前端开发相关广告投放 更专业 更精准

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏