[教程] 在不同的 Laravel 应用中提供(服务端)和使用(客户端) OAuth2 认证

Laravel

介绍

我经常在思考一个问题,即如何让用户使用他们在中心程序上拥有的单个帐户登录到单独的(子)程序。

在这篇文章中,我尝试通过使用 Laravel Passport (example.com) 创建一个中心程序来说明如何使用此基础架构。用户要在中心程序中注册一次,然后使用 OAuth2 权限授予其他应用使用 Laravel Socialite 访问他们账户的权限 (app1.example.comapp2.example.com,等)。 注意: 应用程序不一定必须使用相同的域。

通过这种方式,用户将能够登录到子应用程序,而无需创建新的帐户。

Authorization request (Laravel Passport)

授权请求(Laravel Passport)

如果您还不熟悉 OAuth2 协议,那么我将在下面提供有关操作方法和内容的部分。

什么是 OAuth2?

在讲 Laravel Passport 之前,理解它所实现的 OAuth 协议很重要。

OAuth 是一个开放标准,旨在提供 API 访问委派。你可以设想一个 第三方 Twitter 应用程序,它可以 代表您 发布推文到 Twitter 平台。我明确提到 Twitter,是因为 OAuth 标准的开发主要由 Blane Cook(以及其他开发人员)推动,并且需要外部各方的授权。

在 2010年首次发布 1.0版之后,该协议在发布 2.0版之后的两年中逐渐成熟。改进的协议为 Bearer tokens 提供支持,并为 Web 应用程序、桌面应用程序、移动电话和智能手机提供特定的 authorization flows。 (Wikipedia)

让我们看一下术语 「Bearer token」 和 「authorization flow」 的含义。

Bearer Tokens

"Bearer" 一词表示您拥有某个特定的(访问)令牌。Bearer 是第三方应用程序,它拥有由 身份提供者 颁发的 访问 令牌。该令牌提供对某个资源的 立即访问,而无需用户名和密码。所有必要的信息都链接到此令牌,包括用户详细信息以及此第三方代表该用户可能执行的操作的 作用域

Bearer Token 通常包含在对 API 端点的 GET 或 POST 的请求头中。 下面显示了一个使用 Bearer Token 的具体示例,使用 Guzzle HTTP library 向相应的 API 端点 「/api/user」 发出 GET 请求,附带一个 Bearer 授权头。

$response = $client->request('GET', '/api/user', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer ' . $accessToken,
    ],
]);

授权流程

现在我们知道了不记名访问令牌( Bearer access token )是什么,那我们如何获得一个?

首先,让我们看一下 OAuth2 中的正式角色:

  • 资源所有者: 想要登录并将其帐户详细信息的访问权委派给第三方应用程序的用户
  • 资源服务器: 用户拥有帐户的服务器( API )
  • 客户端: 想要访问资源服务器上帐户信息的第三方应用程序

OAuth 2.0 协议在客户端资源服务器之间执行一个标准的通信流,其中每个步骤和给定/需要的参数都是实现定义的。 最终,客户端资源服务器接受不记名访问令牌 。这个过程如下图所示(使用 draw.io 创建)。注意:假设客户端(第三方应用程序)已向资源服务器注册。

The OAuth authorization flow

OAuth 授权流程

经过上面的流程后,客户现在拥有一个访问令牌,该令牌可以是长期的也可以是短期的(更安全)。如果访问令牌是短期的,则资源服务器还将提供刷新令牌,可将其与客户端密码结合使用以获取新的令牌。访问令牌的方式类似于上图中的第3步。 注意:state 参数用于通过验证请求是否为伪造来防止与 CSRF 相关的攻击。

现在,让我们看看 Laravel Passport 如何实现此协议。

Laravel Passport

在我们的示例中,我们希望身份提供者( example.com )使用Laravel Passport。

Laravel Passport是基于 League OAuth2 server 构建的 OAuth2 服务器。通过要求 composer 软件包,为现有的 Laravel 应用程序提供了简单的实现。

设置资源服务器

请遵循明确的 安装说明 和观看 有关 Laracast 的说明。 不要忘记将 hasApiTokens 特征添加到您的用户模型。

安装后,你现在可以添加新的客户端,具有回调 URL 和自动生成的 密码。对于每个「子」应用程序( app1.example.comapp2.example.com 等),你需要使用自己的应用程序创建一个新的客户端回调,例如,您现在可以选择https://app1.example.com/login/callback(我们将返回到此)。

Creating a new Client in Laravel Passport

在 Laravel Passport中创建新客户端

Laravel Passport 将处理授权对话框,提供授权码,结合授权码验证客户端密码,最后提供一个User对象和(默认情况下)一个长期有效的访问令牌。访问和刷新令牌的生命周期是 可配置的

Example of a Client having an ID and a secret (in Laravel Passport)

具有ID和密码的客户端示例(在 Laravel Passport 中)

Laravel Socialite

现在我们已经完成了资源服务器(身份提供者)的设置,接下来要处理客户端方面的事情。

除了 Passport ,Laravel 还提供了一个名为 Laravel Socialite 的软件包,该软件包在通过 OAuth2 进行身份验证时将负责客户端方面的工作。

开箱即用,它支持使用 Facebook、 Twitter、 LinkedIn、 Google、 GitHub、 GitLab 和 Bitbucket 等服务进行身份验证。

Socialite 提供商

还有一些 其他提供商,其中一个供应商支持 Laravel Passport

设置客户端

为了在多个 Laravel 应用程序之间实现共享登录系统,我提出的解决方案涉及使用 Laravel Passport 的 Socialite 提供商

查看 Socialite 提供程序的安装说明,有很多步骤可以确保客户端应用程序能够使用 Laravel Passport 身份提供程序来识别用户。

  1. 安装 Laravel Socialite
  2. 为 Socialite 安装 Laravel Passport 提供商 
  3. 向 LoginController 控制器添加方法
  4. 复制 laravelpassport 配置 到 config/services.php
  5. 向 EventServiceProvider 添加名为 SocialiteWasCalled 事件和监听器

现在,对于我们可能已经拥有并连接到到资源服务器的每个客户端应用程序来说,这似乎需要重复很多步骤。这也是为什么我创建了一个包(参见 GitHub ),该软件包将 Laravel Socialite 与 Passport 驱动程序结合在一起,并且可以以更有效的方式进行配置。

Laravel Socialite

Now that we have set-up the Resource Server (identity provider), we need to take care of the Client side of things.

Besides Passport, Laravel offers a package called Laravel Socialite, which will take care of the Client side of things when authenticating via OAuth2.

Out of the box, it allows authentication with the services of FacebookTwitterLinkedInGoogleGitHubGitLab and Bitbucket.

Socialite Providers

However, there is a collection of additional providers, amongst which an adapter supporting Laravel Passport.

Setting up the Client

To achieve a shared login system across multiple Laravel applications, my proposed solution involves making use of the Socialite provider for Laravel Passport.

Looking at the installation instructions of the Socialite provider, there are quite a number of steps, to make sure a client application is able to identify users using the Laravel Passport identity provider.

  1. Install Laravel Socialite
  2. Install Laravel Passport provider for Socialite
  3. Add methods to LoginController
  4. Copy the 'laravelpassport' config to config/services.php
  5. Add 'SocialiteWasCalled' event and listener to EventServiceProvider

Now, this seems like a lot of steps to repeat for every Client application we might already have and want to couple to our Resource Server. That's why I made a package (see GitHub repository) that combines Laravel Socialite with the Passport driver and can be configured in a more efficient way.


Socialite-Passport 包

在一个要相称到 Passport 资源服务器 的 Laravel 客户端 应用程序中,首先安装 'socialite-passport' 包:

composer require jhnbrn90/socialite-passport

然后,发布配置文件:

php artisan vendor:publish --provider="JhnBrn90\SocialitePassport\SocialitePassportServiceProvider" --tag="config"

这将在 config 目录中发布 socialite-passport.php 文件,您可以在其中定义哪个控制器(默认为 Laravel 附带的 LoginController) 和登录路由(也可配置)被调用时使用哪个方法。
This will publish a file socialite-passport.php in the config directory, in which you can define which Controller (defaults to LoginController that ships with Laravel) and which method should be called when the login route (also configurable) is called.

return [
    'controller' => [
        'class' => \App\Http\Controllers\Auth\LoginController::class,
        'method' => 'loginWithPassport',
    ],

    'route' => [
        'name' => 'login',
        'uri' => '/login',
    ],
];

假设上述配置为默认设置,则在 资源服务器(Laravel Passport) 中的 资源所有者 授予授权后,loginWithPassport() 方法被调用,并且 User 对象将被注入。该方法需要在定义的控制器中实现(在我们的示例中为 LoginController):

class LoginController extends Controller 
{
    public function loginWithPassport($user) 
    {
        // example:
        User::firstOrCreate(['name' => $user['name'], 'email' => ...]);
    }
}

为了能够为 资源服务器 提供 client_idcallback_uri 等,您必须将以下变量添加到 .env 文件中:

LARAVELPASSPORT_CLIENT_ID=
LARAVELPASSPORT_CLIENT_SECRET=
LARAVELPASSPORT_REDIRECT_URI=/login/callback
LARAVELPASSPORT_HOST=https://example.com

请记住,LARAVELPASSPORT_CLIENT_ID 和 LARAVELPASSPORT_CLIENT_SECRET 来自于 Laravel Passport 资源服务器,首先要创建 客户端

该软件包将确保与您作为 LARAVELPASSPORT_REDIRECT_URI 环境变量提供的路由相匹配,并通过您在配置文件中配置的相应方法和控制器代理请求。


结束语

这就是实现基本功能共享登录系统所需要的全部。

我希望这篇文章能对 OAuth2 协议以及如何与上述工具一起使用以在不同的 Laravel 项目之间实现共享的身份验证系统有所启发。

最好在用户模型中存储访问令牌(和资源令牌),以便每当用户在 资源服务器 上更改其配置文件时就能够更新信息。或者当然也可以从资源服务器收集该用户的其他数据。

摘要

  • Laravel Passport 实现了功能齐全的 OAuth2 服务器(资源服务器)
  • Laravel Socialite 实现了一种通过 OAuth2 服务器进行身份验证的方法(客户端)
    • Laravel Passport 的 Socialite provider 允许使用 Laravel Passport 进行身份验证
    • 可以使用 此程序包 将客户端准备就绪,将 Socialite 与 Passport 适配器组合在一起
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://johnbraun.blog/posts/oauth2-auth...

译文地址:https://learnku.com/laravel/t/41648

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!