角度CAS认证

Max*_*Max 5 cas cakephp single-sign-on jwt angular

我正在构建一个仪表板,旨在简化多个业务应用程序的使用。仪表板的主要工作是从这些应用程序中获取数据并将它们发送回经过身份验证的用户。仪表板分为使用框架 CakePHP3 编写的 API 和一个只执行 HTTP 请求的客户端(尚未编写,但计划在 angular(2+) 中)。

流程示例:我登录仪表板,它告诉我应用程序 A 中有 5 封未读电子邮件,应用程序 B 中有 3 个通知,应用程序 C 中有 5 个新文档。对于收到的每个数据,我有一个直接链接来访问目标业务应用程序中的这些数据。

为此,所有业务应用程序都被cassified(CAS客户端),仪表板充当代理CAS(经过身份验证的用户的身份被传输到cassified应用程序)。

这是一个架构图来解释我们的目标

我编写了一个 CakePHP3 插件来对 CAS 服务器进行身份验证。该插件很简单,如果我没有 CAS 会话(通过 phpCAS),它会将我重定向到 CAS。

在我的后端,我有一个端点允许我对业务应用程序进行代理请求,我们称之为 :(/api/business/:id其中 :id 是应用程序的 ID)。这是我当前使用 phpCAS 执行此代理请求的代码:

if (!phpCAS::isAuthenticated()) {
    throw new ForbiddenException('You need to be authenticated to the CAS server.');
}
$this->service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
$this->service->setUrl($this->url);
try {
    $this->service->send();
    $this->responseCode = $this->service->getResponseStatusCode();
    $this->responseBody = $this->service->getResponseBody();
} 
// willingly removed, not useful in this example
catch () {}
Run Code Online (Sandbox Code Playgroud)

然后我将操纵响应代码和正文以向最终用户显示我需要的内容。

我的主要问题是我应该如何处理角客户端中的身份验证。我尝试了多种方法,但没有找到方便的答案。

尝试 1(客户端中还没有身份验证方法)

它需要一些准备:

第一的

  • 我通过浏览器请求 API
  • 我被重定向到 CAS
  • 我进行身份验证(会话设置在我的 cookie 中)
  • 我被重定向到 API

然后我可以通过简单地在 HTTP 请求中发送 cookie 来使用客户端(使用 {withCredentials : true})。

如果我要使用这种方法,我需要向客户端发送一些处理登录的 PHP 文件。在身份验证时,用户将被重定向到 PHP 登录页面,该页面将处理会话并重定向到 CAS。

尽管它可以工作,但我认为将客户端的请求基于他并不真正意识到的 cookie 会造成更多麻烦,它可能会造成一些登录超时或其他内部问题。这看起来像是“最后的手段”解决方案。

尝试 2(使用 JWT)

我将我的 CAS 身份验证插件更改为现有的 JWT 身份验证插件:https : //github.com/ADmad/cakephp-jwt-auth

我已将cas-server-support-token-webflow依赖项添加到我的 CAS 服务器,并确保在 CAS 和我的 API 之间使用相同的签名密钥。

然后我对 API 进行身份验证,它生成一个 JWT,我存储在 localStorage 中。我正在使用标头进行经过身份验证的请求:Authorization: Bearer <MY_TOKEN>

当客户端请求执行代理请求的端点时,我拦截授权标头。我已将执行代理请求的代码(见上文)更改为类似的代码:

$url = CAS_LOGIN_URL . '?service=' . urlencode($this->url) . '&token=' . INTERCEPTED_AUTHORIZATION_TOKEN;
// Authenticate to CAS and get a ST
$response = $http->get($url); //  Location header : SERVICE_URL?ticket=ST-...
// Validate the ST
$response = $http->get($response->getHeader('Location')[0]) // Location header : SERVICE_URL
// ST is validated, finally get data
$response = $http->get($response->getHeader('Location')[0])
$this->responseCode = $response->getStatusCode();
$this->responseBody = $response->getBody();
Run Code Online (Sandbox Code Playgroud)

这个流程更有趣,因为它确实是无状态的。主要问题是我在浏览器端没有会话。这意味着我将向最终用户发送数据(参见上面的模式),当用户单击链接时,他不会被重定向到业务应用程序,而是被重定向到 CAS,在那里他需要再次进行身份验证才能创建他自己的会议。

为了防止这种情况,我可以向他展示一个像这样的伪造网址:https://<CAS_LOGIN_URL>?service=<ENCODED_BUSINESS_APP_URL>&token=<TOKEN_IN_LOCALSTORAGE>。然而,这是一个安全漏洞,因为令牌将存储在用户历史浏览器中,在来自服务器的日志中,用户也可能通过从链接进行复制/粘贴来泄漏它。

尝试 3(使用 CAS REST 协议)

我没有尝试太多这个解决方案,但我遇到了与 JWT 解决方案类似的问题,所以我有点放弃了它(也许这是一个错误?)

基本上我认为 JWT 选项是正确的,但我无法安全地验证我的用户,这让我认为我的第一次尝试可能更安全但不太可靠。这就是为什么我想听听你对我所做的事情的看法(如果我没有遗漏什么的话)以及在我的情况下我最好的行动方案是什么。

谢谢。