使用Auth0构建和保护一个简单的Symfony API服务器

174 阅读8分钟

**TL;DR:**在这篇文章中,你将学习如何从头开始建立一个Symfony API服务器。你还将进一步确保一些端点的安全。你将使用Auth0来处理认证和授权。本教程的完整源代码可以在GitHub上找到。

前提条件

要继续学习本教程,你应该具备合理的PHP面向对象编程知识,以及使用Symfony构建应用程序的基本知识。你还需要以下条件。

你将建立什么

你将建立一个简单的Symfony API服务器,有三个不同的端点。每个端点将根据用户的访问权限,返回不同类型的信息。

公共端点

  • GET /api/messages/public

这个端点应该暴露给任何未经授权的人。预计它将返回以下消息。

{
  "message": "The API doesn't require an access token to share this message."
}

受保护的端点

  • GET /api/messages/protected

这个端点将被保护起来,防止未经授权的访问。只有在其HTTP请求头中具有有效访问令牌的授权用户才能看到以下消息。

{
  "message": "The API successfully validated your access token."
}

管理员端点

  • GET /api/messages/admin

与受保护的端点类似,这需要访问令牌包含一个 read:admin-messages访问管理数据的权限。这通常被称为基于角色的访问控制(RBAC)

开始使用

在这里,你将通过设置和安装一个新的Symfony应用程序及其所需的依赖项开始构建Symfony API。

构建Symfony应用程序的支架

首先,打开你的终端,导航到你喜欢的开发目录,并发出以下命令,用Composer搭建一个新项目。

composer create-project symfony/website-skeleton api-symfony-server

一旦安装过程完成,切换到你刚刚创建的新目录。

cd api-symfony-server

```bash
cp .env .env.local

这个文件被Git忽略了,因为它符合一个现有的模式 .gitignore(Symfony生成的)。这个文件的好处之一是,它有助于在代码之外存储你的凭证,以保证它们的安全。

接下来,更新 DATABASE_URL中的参数 .env.local中的参数,使应用程序使用SQLite数据库,而不是默认的PostgreSQL。要做到这一点,注释掉现有的 DATABASE_URL条目,并取消对SQLite选项的注释,使其与下面的例子一致。

DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"

注意:数据库将在项目根目录的var目录下创建,并命名为 data.db.

运行应用程序

确保你在主项目目录中,使用Symfony CLI,用以下命令启动应用程序。

symfony serve

导航到http://localhost:8000,查看新Symfony应用程序的默认主页。

Symfony Homepage

构建API

在本节中,我们将重点创建控制器,处理前面提到的每个端点的逻辑。我们将从公共端点开始,逐步处理其他端点。

停止应用程序的运行,使用 CTRL + C停止应用程序的运行,然后点击Enter

创建控制器并配置每个端点

首先从你项目根目录下的终端发出以下命令,创建一个控制器。

php bin/console make:controller APIController

你会看到下面的输出。

 created: src/Controller/APIController.php
 created: templates/api/index.html.twig

  Success!

 Next: Open your new controller class and add some pages!

找到新创建的控制器,在 src/Controller/APIController.php中新建的控制器,并将其内容更新为以下内容。

// src/Controller/APIController.php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/api/messages")
 */
class APIController extends AbstractController
{
    /**
     * @Route("/public", name="public")
     */
    public function publicAction()
    : JsonResponse
    {
        return $this->json(["message" => "The API doesn't require an access token to share this message."], Response::HTTP_OK);
    }

    /**
     * @Route("/protected", name="protected")
     */
    public function protectedAction()
    : JsonResponse
    {
        return $this->json(["message" => "The API successfully validated your access token."], Response::HTTP_OK);
    }

    /**
     * @Route("/admin", name="admin")
     */
    public function adminAction(): JsonResponse
    {
        return $this->json(["message" => "The API successfully recognized you as an admin."], Response::HTTP_OK);
    }
}

从上面的片段来看,这个控制器包含三个不同的方法。

  • publicAction()
  • protectedAction()
  • adminAction()

每一个都被设计用来处理 /public, /protected/admin端点,并分别返回相应的消息。

回到终端,用symfony serve ,再次启动应用程序,打开API测试工具,如Postman,测试每个端点。

从公共端点开始。创建一个新的GET请求到这个端点http://localhost:8000/api/messages/public。你将得到消息 The API doesn't require an access token to share this message,如下图所示。

Public Endpoint Using Postman

接下来,在http://localhost:8000/api/messages/protected,尝试一下受保护的端点

Protected Endpoint using Postman

最后,[http://localhost:8000/api/messages/admin](http://localhost:8000/api/messages/admin)上的管理端点将给你带来消息 The API successfully recognized you as an admin.:

Admin Endpoint using Postman

目前,所有创建的端点都可以被任何人访问。当然,这不是我们想要的。你需要确保 /protected/admin端点只暴露给授权用户。你将在下一节开始进行配置。

如果你还没有,请确保你现在创建一个免费的Auth0账户

保护受保护端点和管理端点的安全

你将使用Auth0来保护端点(受保护和管理)。要做到这一点,你将需要回到你的Auth0仪表板,并配置一个API。

首先,通过点击 "应用">"API "导航到你的Auth0管理仪表盘的API部分。如果你以前创建过任何API,这将显示你账户的所有API列表,但在本教程中,继续点击**"CREATE API "**按钮,设置一个新的。

Create New API

为API提供一个友好的名字,如 Symfony API Server并将其标识符设置为 https://localhost:8000.你可以自由地使用任何名称和标识符,但如果你想完全遵循本教程,你应该保持上述数值。将签名算法设为 RS256并点击**"创建 "**按钮来继续。在本教程的后面,你将需要这里的值。

安装依赖项并配置认证

为了确保 GET /api/messages/protectedGET /api/messages/admin端点的安全,你将使用Symfony的JWT认证包,名为auth0/jwt-auth-bundle

停止应用程序的运行,使用 CTRL + C并运行下面的命令,用composer安装这个包。

composer require auth0/jwt-auth-bundle:"~4.0"

在你的项目中安装捆绑包后,你应该发现一个新文件,位于 config/packages/jwt_auth.yaml.如果没有,请创建该文件并在其中粘贴以下内容。

jwt_auth:
  domain: "%env(AUTH0_DOMAIN)%"
  client_id: "%env(AUTH0_CLIENT_ID)%"
  audience: "%env(AUTH0_AUDIENCE)%"

早些时候,当你创建一个API时,Auth0也自动为你的API创建了一个测试应用程序。这将是容纳你的用户的Auth0应用程序。你可以通过点击Applications >Applications ,然后从列表中选择与你的API命名相匹配的测试应用程序来找到它。如果你的名字和本教程中的一样,它将是 "Symfony API服务器(测试应用)"。你也可以为你的账户选择和使用任何其他应用程序。但在本教程中,点击测试应用程序,你会看到一个如图所示的页面。

Test Application

打开 .env.local文件并更新以下环境变量的值。

CLIENT_ORIGIN_URL=http://localhost:4040
AUTH0_AUDIENCE=http://localhost:8000
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_CLIENT_ID=YOUR_AUTH0_ID
AUTH0_CLIENT_SECRET=YOUR_AUTH0_CLIENT_SECRET

确保替换 YOUR_AUTH0_DOMAIN, YOUR_AUTH0_CLIENT_IDYOUR_AUTH0_CLIENT_SECRET用从你的Auth0仪表板上获得的适当的值来取代占位符。

设置用户和用户提供者

处理认证和授权需要Auth0知道当前认证的用户。这是Symfony中User provider的工作,因为它有助于从会话中重新加载用户,并为其他特定功能加载用户,如使用用户名或电子邮件进行认证。

如果我们的API的用户存储在数据库中,创建一个自定义的用户提供者可能没有必要,但在这里,我们将从一个自定义位置(Auth0)加载用户,因此需要创建一个。

首先,导航到src 文件夹,创建一个新的文件夹,命名为Security ,在新创建的文件夹中,再创建一个文件夹,命名为User 。接下来,在User 文件夹中创建用户类,并将其命名为 WebServiceUser.php.打开新创建的文件,把下面的代码粘贴进去。

<?php

namespace App\Security\User;

use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class WebServiceUser implements
    UserInterface, EquatableInterface {

    private $roles;
    private $jwt;

    public function __construct($jwt, $roles) {

        $this->roles = $roles;
        $this->jwt = $jwt;
    }

    /**
     * @inheritDoc
     */
    public function getRoles()
    : array {

        return $this->roles;
    }

    /**
     * @inheritDoc
     */
    public function getPassword()
    : ?string {

        return null;
    }

    /**
     * @inheritDoc
     */
    public function getSalt()
    : ?string {

        return null;
    }

    public function isEqualTo(UserInterface $user)
    : bool {

        if (!$user instanceof WebServiceUser) {
            return false;
        }

        return $this->getUsername() === $user->getUsername();
    }

    /**
     * @inheritDoc
     */
    public function getUsername() {

        return $this->jwt["email"] ?? $this->jwt["sub"];
    }

    /**
     * @inheritDoc
     */
    public function eraseCredentials() {
    }

    public function getUserIdentifier() {
        return $this->jwt["email"] ?? $this->jwt["sub"];
    }
}

在这里,WebServiceUser 类实现了两个不同的接口。

接下来,在User 文件夹中创建一个文件,并将其命名为 WebServiceAnonymousUser.php.这将返回匿名用户。使用下面的内容。

<?php

namespace App\Security\User;

class WebServiceAnonymousUser extends WebServiceUser {

    public function __construct() {

        parent::__construct(null, ['IS_AUTHENTICATED_ANONYMOUSLY']);
    }

    public function getUsername() {

        return null;
    }
}

为了收尾,在User 文件夹中创建另一个文件,并将其命名为 WebServiceUserProvider.php.完成后,在其中粘贴以下代码。

<?php

namespace App\Security\User;

use Auth0\JWTAuthBundle\Security\Core\JWTUserProviderInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Polyfill\Intl\Icu\Exception\NotImplementedException;


class WebServiceUserProvider implements JWTUserProviderInterface {

    public function loadUserByJWT($jwt)
    : WebServiceUser {
        $data = ['sub' => $jwt->sub];
        $roles = [];
        $roles[] = 'ROLE_OAUTH_AUTHENTICATED';

        return new WebServiceUser($data, $roles);
    }

    public function getAnonymousUser()
    : WebServiceAnonymousUser {

        return new WebServiceAnonymousUser();
    }

    public function loadUserByUsername($username) {

        throw new NotImplementedException('method not implemented');
    }

    public function refreshUser(UserInterface $user) {

        if (!$user instanceof WebServiceUser) {
            throw new UnsupportedUserException(
                sprintf('Instances of "%s" are not supported.', get_class($user))
            );
        }

        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class)
    : bool {

        return $class === 'App\Security\User\WebServiceUser';
    }

    public function loadUserByIdentifier(string $identifier)
    {
        throw new NotImplementedException('method not implemented');
    }
}

这个类实现了前面安装的Auth0捆绑包中的JWTUserProviderInterface ,它规定了WebServiceUserProvider 类必须实现的重要方法。这些方法是。

  • loadUserByJWT:它接收解码后的JWT访问令牌并返回一个用户。
  • getAnonymousUser: 返回一个匿名用户,代表一个未经认证的用户(通常由角色代表 IS_AUTHENTICATED_ANONYMOUSLY)

创建一个Guard Authenticator

接下来,我们需要在Symfony中创建一个guard authenticator。要做到这一点,在Symfony文件夹中创建一个新文件,并命名为 src/Security/User文件夹中创建一个新文件,并将其命名为 GuardAuthenticator.php.打开新文件并使用以下内容。

<?php


namespace App\Security\User;


use Auth0\JWTAuthBundle\Security\Guard\JwtGuardAuthenticator;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;

class GuardAuthenticator extends JwtGuardAuthenticator
{
    public function start(Request $request, AuthenticationException $authException = null)
    {
        $responseBody = [
            'message' => 'No authorization token was found',
        ];

        return new JsonResponse($responseBody, JsonResponse::HTTP_UNAUTHORIZED);
    }
}

这个GuardAuthenticator 扩展了jwt 捆绑包中的JwtGuardAuthenticator 类,并检查HTTP请求头中是否存在访问令牌。如果没有,它会返回一个适当的消息。

配置安全提供者

在配置安全提供者之前,为WebServiceUserProvider ,创建一个服务。服务是使你的应用程序更容易维护和适应新要求的一个好方法。你可以通过在文件的底部添加以下代码来创建一个 config/services.yaml文件的底部来创建。

parameters:

services:
    ...
    # 👇  new code starts here
    web_service_user_provider:
        class: App\Security\User\WebServiceUserProvider
        arguments: ["@jwt_auth.auth0_service"]

最后,修改 security.yaml文件中的 config/packages/security.yaml文件,使其包含以下内容。

  • web_service_user_provider 服务
  • 你想用访问令牌来验证的安全区域
  • access_control 部分,其中包含每条路线所需的角色 你可以用以下内容完全取代它。
security:
  enable_authenticator_manager: true

  # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
  providers:
    #        users_in_memory: { memory: null }
    web_service_user_provider:
      id: App\Security\User\WebServiceUserProvider
  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js)/
      security: false
    secured_area:
      pattern: ^/api
      stateless: true
      guard:
        authenticators:
          id: App\Security\User\GuardAuthenticator
      provider: web_service_user_provider
  # Easy way to control access for large sections of your site
  # Note: Only the *first* access control that matches will be used
  access_control:
    - { path: ^/api/messages/public, roles: PUBLIC_ACCESS }
    - { path: ^/api/messages/protected, roles: ROLE_OAUTH_AUTHENTICATED }
    - { path: ^/api/messages/admin, roles: ROLE_OAUTH_AUTHENTICATED }

现在,你可以通过访问受保护的路由,用Postman再次测试这个。通过运行symfony serve ,启动应用程序,访问 http://localhost:8000/api/messages/protected.你会收到一条信息,表明 "没有找到授权令牌",如下图所示。

No token found

这是因为你需要一个访问令牌来成功地从终端检索内容。 /protected端点的内容。

即时生成访问令牌需要你的客户端应用程序得到Auth0的授权,但作为一个概念证明,现在,你将从Auth0仪表板上为你的API获得并使用一个测试令牌。要做到这一点,请浏览你的Auth0仪表板中的API部分,点击你先前创建的API。接下来,点击Test 标签,向下滚动,复制响应副标题下显示的access_token

再次打开Postman,从授权标签中选择Bearer Token ,然后粘贴访问令牌。

Bearer Token

现在你可以尝试使用受保护的 api/messages/protected端点,你会得到如下信息 The API successfully validated your access token.,如下图所示。

Protected Endpoint Response

为API实现基于角色的访问控制

如前所述,该 GET /api/messages/admin端点需要访问令牌包含一个 read:admin-messages权限来访问管理数据。这通常被称为基于角色的访问控制(RBAC),即必须根据用户在组织中的角色为其分配权限。

在本节中,为了实现和配置这种访问控制,你将做以下工作。

  • 在你的Auth0仪表板中启用RBAC(基于角色的访问控制)设置
  • 在仪表板内创建一个admin 角色
  • 创建特定的权限。 read:admin-messages以此为准确。
  • 将新创建的权限添加到admin 角色中。
  • 将新的角色分配给一个特定的用户

启用RBAC设置

为了使基于角色的访问控制(RBAC)正常工作,你必须使用仪表板或管理API为你的API启用它。

导航到你的Auth0仪表板,点击API,然后选择先前创建的API Symfony API Server然后向下滚动到RBAC设置部分。

RBAC Settings

通过拨动这里的两个按钮来启用RBAC。"启用RBAC "和 "在访问令牌中添加权限"。这将为任何选择的端点强制执行基于角色的访问控制授权策略,并确保permissions ,并将其添加到访问令牌中。点击 "保存"按钮来更新这些变化。

创建一个管理员角色

你可以使用Auth0的仪表板或管理API来创建角色。这些角色可以与API授权核心功能集一起使用。

转到下面。

  • 仪表板
  • 从侧面的菜单栏点击用户管理
  • 点击角色
  • 接下来,点击创建角色按钮

给角色起个名字,如 "管理员",并添加一个描述,如 "阅读所有管理员信息"。

Create New Role

创建权限

返回到 Symfony API Server从仪表板上的API菜单返回到 "权限 "页面,并在同一页面上点击 "权限 "标签,以定义权限及其范围。

在 "权限(范围),粘贴 read:admin-messages.对于 "描述",把 "阅读管理信息"。确保你点击 "添加 "来保存该权限。

Create Permission

为角色添加权限

现在你已经创建了Admin 角色及其相应的权限,接下来要做的是将权限添加到新创建的角色中。

回到 "用户管理">"角色 "中的 "角色 "页面。

List of Roles

点击您之前创建的 "管理员 "角色,然后点击 "权限 "标签。现在点击 "添加权限 "按钮。你会看到一个像这样的页面。

Add Permission

从列表中选择API;在我们的例子中,这将是 Symfony API Server.勾选旁边的方框 read:admin-messages来表示管理员角色的权限。最后,点击 "添加权限"以保存更改。

给用户分配角色

有两种方法可以给用户分配角色。你可以从用户列表中选择一个用户,然后分配一个角色,或者你可以进入单个用户的用户详情(用户配置文件)页面,在 "角色"选项卡中选择一个角色来分配。在本教程中,你将坚持使用 "用户 "列表。

要做到这一点。

  1. 进入仪表板 > 用户管理 > 用户
  2. 点击你想修改的用户旁边的**"...",并选择分配角色**。
  3. 选择你想分配的角色,然后点击分配

Assign Role to User

更新网络服务用户提供者

在这一点上,一旦用户通过API认证,将返回的access token ,要么包含一个 read:admin-messages权限或不包含。为了在允许用户访问管理数据之前检查这个权限,你将更新 src/Security/User/WebServiceUserProvider.php文件,如下图所示。

...
class WebServiceUserProvider implements JWTUserProviderInterface {

    public function loadUserByJWT($jwt)
    : WebServiceUser {
        $data = ['sub' => $jwt->sub];
        $roles = [];
        $roles[] = in_array('read:admin-messages', $jwt->permissions) ? 'ROLE_ADMIN' : 'ROLE_OAUTH_AUTHENTICATED';

        return new WebServiceUser($data, $roles);
    }
    ...
}

这里,你检查了 read:admin-messages是否存在于权限数组中。如果存在,那么一个角色的 ROLE_ADMIN的角色将被分配给认证的用户。否则,一个角色 ROLE_OAUTH_AUTHENTICATED将被分配。

另外,打开 config/packages/security.yaml并更新其内容,如下面所示。

security:
  enable_authenticator_manager: true

  # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
  providers:
    #        users_in_memory: { memory: null }
    web_service_user_provider:
      id: App\Security\User\WebServiceUserProvider
  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js)/
      security: false
    secured_area:
      pattern: ^/api
      stateless: true
      guard:
        authenticators:
          id: App\Security\User\GuardAuthenticator
      provider: web_service_user_provider
  role_hierarchy:
    ROLE_ADMIN: [ROLE_OAUTH_AUTHENTICATED, ROLE_ALLOWED_TO_SWITCH]
  # Easy way to control access for large sections of your site
  # Note: Only the *first* access control that matches will be used
  access_control:
    - { path: ^/api/messages/public, roles: PUBLIC_ACCESS }
    - { path: ^/api/messages/protected, roles: ROLE_OAUTH_AUTHENTICATED }
    - { path: ^/api/messages/admin, roles: ROLE_ADMIN }

从上面的片段中,你更新了角色的 api/messages/admin端点的角色。

创建一个事件订阅者

一旦一个未经授权的用户在没有适当权限的情况下试图访问任何一个 /api/messages/admin端点,就会抛出一个异常,表明这种访问是被禁止的。

在这一节中,你将创建一个事件订阅器,它将监听被禁止的事件并返回一个适当的消息。要做到这一点,在src 目录中创建一个名为EventSubscriber 的文件夹,然后在其中创建一个名为 ExceptionSubscriber.php的新文件。打开新创建的文件,为其使用以下内容。

<?php

namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

class ExceptionSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => ['onKernelException']
        ];
    }

    public function onKernelException(ExceptionEvent $event)
    {
        $exception = $event->getThrowable();
        if ($exception instanceof AccessDeniedHttpException) {
            $event->setResponse(new JsonResponse([
                'message' => "Insufficient scopes.",
            ], Response::HTTP_UNAUTHORIZED));
            $event->stopPropagation();
        }
        return $exception;
    }
}

在进行了所有必要的修改后,通过发出以下命令运行API服务器。

symfony serve

测试管理端点

如前所述,与到目前为止创建的其他端点不同,这个 GET /api/messages/admin端点要求访问令牌含有 read:admin-messages权限。由于从Auth0仪表板上的机器对机器应用程序中操作访问令牌有点困难,也不可取,我们将采取不同的方法,使用一个客户端应用程序来模拟和测试客户端与服务器的交互。

这是目前最好的方法,以确保我们有一个界面供用户使用。

  • 登录和注销
  • 检索用户档案信息
  • 保护应用程序路线
  • 对API进行安全调用

注意:请随意使用你的客户端应用程序,如果有的话,用于这个过程。

要使用预先建立的客户端应用程序,从终端发出以下命令,从GitHub克隆该应用程序。

git clone https://github.com/auth0-sample-gallery/spa_angular_typescript_hello-world.git hello-world-demo

这将在你的开发目录中的一个新文件夹中克隆演示应用程序,该文件夹名为 hello-world-demo的新文件夹中。

在安装项目的依赖项之前,确保你已经安装了Angular CLI。你可以通过在你的系统终端发出这个命令来验证。

ng --version

输出将是你系统上当前安装的Angular CLI版本的详细信息。如果没有安装,请按照这里的说明全局配置Angular CLI

移动到新项目的文件夹中,发出以下命令来安装所需的依赖项。

// Change directory
cd hello-world-demo

// Install dependencies
npm install

启动项目使用自定义的样式表来设计和布局应用程序,所以你不需要做任何改动。

将客户端应用程序连接到Auth0

接下来,你需要把这个应用程序连接到Auth0。回到你的Auth0仪表板,点击 "应用">"应用">"创建应用"。

给它起个名字,如 "Angular Symfony App",并选择 "Single Page Web Applications "作为应用程序的名称。最后,点击 "创建"。

Auth0

只要有认证请求,Angular演示应用程序将把用户重定向到Auth0登录页面。然后,Auth0将带着必要的凭证重定向回来。

为了使重定向安全地发生,你必须指定Auth0在验证了用户的凭证后可以重定向到的URL。回到Auth0仪表板,选择为你的API创建的应用程序,点击该页面上的设置标签,向下滚动以找到以下字段。

  • 允许的回调URLs
  • 允许的网络源头
  • 允许的注销URLs

使用 http://localhost:4040作为每个字段的值,因为在开发过程中,客户端应用程序将可以通过该URL访问。点击 "保存更改"来继续。

在正确指定了URL后,用Auth0连接客户端应用程序,在客户端应用程序的根目录下创建一个新文件,名为 env.json的新文件,并按这里所示填充该文件。

{
  "domain": "YOUR_AUTH0_DOMAIN",
  "clientId": "YOUR_AUTH0_CLIENT_ID",
  "audience": "http://localhost:8000",
  "apiServerUrl": "http://localhost:8000"
}

确保你在 "域名 "和 "客户ID "中填写你在Auth0仪表板的应用程序页面中的值。 现在,继续使用以下命令运行该应用程序。

ng serve

导航到http://localhost:4040,访问该应用程序。

Angular Demo App Page

启用客户端应用程序和Symfony API服务器之间的通信

默认情况下,浏览器有安全措施,禁止不同域的应用程序之间的互动和资源共享,除非任何一个应用程序明确允许。这意味着目前从客户端应用程序向Symfony API发送HTTP请求将被禁用。为了使两个应用程序之间能够进行通信,你将需要启用CORS(跨源资源共享)

为了启用Symfony API,你将需要使用Nelmo Bundle。运行下面的命令来安装它。

composer require nelmio/cors-bundle

一旦安装过程完成,一个名为 nelmio_cors.yaml的默认配置文件将被生成在 config/packages文件夹中,如图所示。

nelmio_cors:
  defaults:
    origin_regex: true
    allow_origin: ["%env(CORS_ALLOW_ORIGIN)%"]
    allow_methods: ["GET", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"]
    allow_headers: ["Content-Type", "Authorization"]
    expose_headers: ["Link"]
    max_age: 3600
  paths:
    "^/": null

这里指定的默认配置就足够了,因为它说明了所有适当的HTTP动词。接下来,导航到该 .env.local文件并更新其内容,如下图所示。

####> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
####< nelmio/cors-bundle ###

在这里,我们指定应允许使用localhost URL。

最后,用以下命令启动Symfony服务器。

    symfony serve

客户端应用程序中,点击外部API按钮,并提供你的凭证。

确保你用Auth0仪表板上指定的具有管理员角色的用户的详细信息来登录。

View Admin Endpoint Response

你也可以通过点击 "公共"按钮来检查其他端点。 api/messages/public端点的 "公共 "按钮或 "保护"按钮来检查其他端点。 api/messages/protected端点,如下图所示。

View Public Endpoint Response

View Protected Endpoint Response

总结

如本教程所示,你学会了如何轻松地建立一个Symfony API服务器,其中有一个无需认证即可被互联网上的任何人访问的端点,以及其他需要适当授权和角色的端点。

你从公共端点开始陆续创建了这些端点,并进一步创建了两个受保护的端点,即私人端点和管理端点。为了完全设置和配置受保护端点的认证和授权,你利用了Auth0的API,以确保只有在授权头中包含有效访问令牌的HTTP请求才能检索到数据。

我希望你觉得这个教程很有帮助。这篇文章中构建的API服务器的完整源代码可以在GitHub上找到。

编码愉快,请随时在下面的评论区分享你的想法和问题。