petrsimunek/laravel-azure-middleware

Azure 中间件身份验证

v1.0.2 2024-05-31 18:18 UTC

This package is auto-updated.

Last update: 2024-10-01 00:08:15 UTC


README

为 Laravel 应用提供 Azure 身份验证中间件。如果您喜欢这个项目,请查看 Laravel Saml 中间件

常规安装

  1. composer require petrsimunek/laravel-azure-middleware
  2. 运行 php artisan vendor:publish --provider="petrsimunek\LaravelAzureMiddleware\AzureServiceProvider" 将配置文件安装到 config/azure.php
  3. 在我们的路由文件夹(通常是 web.php),添加
Route::get('/login/azure', '\petrsimunek\LaravelAzureMiddleware\Azure@azure')
    ->name('azure.login');
Route::get('/login/azurecallback', '\petrsimunek\LaravelAzureMiddleware\Azure@azurecallback')
    ->name('azure.callback');

注意:只有当在门户中配置 redirect_uri 时才需要路由名称。

  1. 在我们的 App\Http\Kernel.php 中添加 'azure' => \petrsimunek\LaravelAzureMiddleware\Azure::class, 通常添加到 $routeMiddleware 数组中。
  2. 在我们的 .env 中添加 AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET 和 AZURE_RESOURCE。我们可以在以下位置获取这些值/了解更多信息:https://portal.azure.com/(提示:AZURE_RESOURCE 应为 https://graph.microsoft.com
  3. 从 0.8.0 版本开始,我们添加了 AZURE_SCOPE,这是用于请求的权限。我们可以在以下位置了解更多关于这些权限的信息:https://docs.microsoft.com/en-us/graph/api/resources/users?view=graph-rest-1.0
  4. 我们还添加了一个可选的 AZURE_DOMAIN_HINT,可用于帮助用户知道他们应该使用哪个电子邮件地址进行登录。更多信息请参阅 https://azure.microsoft.com/en-us/updates/app-service-auth-and-azure-ad-domain-hints/
  5. 在我们的应用程序上 https://portal.azure.com/reply url 指向 /login/azurecallback 路由,使用完整的 URL(例如:http://thewebsite.com/login/azurecallback)。
  6. azure 中间件添加到需要受身份验证保护的任何路由的路由组中,享受 🎉
  7. 如果您需要自定义回调,请参阅 扩展安装

注意:您可能需要为(旧版)Azure Active Directory Graph 添加权限从 0.8.0 版本开始,我们使用 Azure 登录 API 的 v2 版本,这允许我们传递范围或我们希望使用的权限。

路由

Route::get('/login/azure', '\petrsimunek\LaravelAzureMiddleware\Azure@azure')->name('azure.login'); 第一个参数可以指向您希望路由 Azure 登录的位置。根据需要更改。

Route::get('/login/azurecallback', '\petrsimunek\LaravelAzureMiddleware\Azure@azurecallback')->name('azure.callback'); 第一个参数可以指向您希望回调后路由到的任何位置。根据需要更改。

Route::get('/logout/azure', '\petrsimunek\LaravelAzureMiddleware\Azure@azurelogout')->name('azure.logout); 第一个参数可以指向您希望回调后路由到的任何位置。根据需要更改。

注意:只有当在门户中配置 redirect_uri 时才需要路由名称。

前端

最好在登录网页上有一个指向 route('azure.login') 的 Office 365 按钮。这可以是一个简单的锚点标签,例如:<a href="{{ route('azure.login') }}" class="officeButton"></a>

扩展安装

开箱即用的实现允许您让用户登录。但是,假设我们想要将此用户存储到数据库中,并使用 Laravel Auth 登录用户。有两个建议从 Azure 类扩展的回调:名为 successfail。以下提供有关如何扩展 Root Laravel Azure Middleware Library 的信息

  1. 开始之前(假设我们已经按照常规安装说明操作),在App\Http\Middleware文件夹中创建一个名为AppAzure.php的文件。您可以通过artisan命令或手动操作来完成此操作。
  2. 在此文件中将以下内容作为起始点
<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;

use Auth;

use App\Models\User;

class AppAzure extends Azure
{
    protected function success(Request $request, $access_token, $refresh_token, $profile)
    {
        $graph = new Graph();
        $graph->setAccessToken($access_token);

        $graph_user = $graph->createRequest("GET", "/me")
                      ->setReturnType(Model\User::class)
                      ->execute();

        $email = strtolower($graph_user->getUserPrincipalName());

        $user = User::updateOrCreate(['email' => $email], [
            'name' => $graph_user->getGivenName() . ' ' . $graph_user->getSurname(),
        ]);

        Auth::login($user, true);

        return parent::success($request, $access_token, $refresh_token, $profile);
    }
}

以上方法为我们提供了一种在握手成功后添加/更新用户的方式。变量$profile包含各种元数据,我们用它来创建或更新我们的用户。更多信息请参阅:https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code#jwt-token-claims。默认实现重定向到目标URL,或/,因此在这里调用父类。您可以选择不扩展默认实现并重定向到其他地方。

  1. 我们需要更新以下路由
Route::get('/login/azure', '\App\Http\Middleware\AppAzure@azure')
    ->name('azure.login');
Route::get('/login/azurecallback', '\App\Http\Middleware\AppAzure@azurecallback')
    ->name('azure.callback');
Route::get('/logout/azure', '\App\Http\Middleware\AppAzure@azurelogout')
    ->name('azure.logout');
  1. 最后,将Kernel.php中的azure键更新为'azure' => \App\Http\Middleware\AppAzure::class,

其他扩展选项

在每次握手时回调

从v0.4.0版本开始,我们在每次从Azure成功请求(握手)后添加了一个回调。默认操作是简单地调用$next闭包。但是,假设我们想要更新用户。以下是如何进行操作的示例

<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;

use Closure;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;

use Auth;
use Carbon\Carbon;

use App\User;

class AppAzure extends Azure
{
    protected function handlecallback(Request $request, Closure $next, $access_token, $refresh_token)
    {
        $user = Auth::user();

        $user->updated_at = Carbon::now();

        $user->save();

        return parent::handlecallback($request, $next, $access_token, $refresh_token);
    }
}

基于之前的扩展安装示例,现在Auth中有一个用户(因为我们成功回调中执行了Auth::login)。利用用户模型,我们可以更新用户的updated_at字段。回调应该调用闭包$next($request);并返回它。在我们的情况下,默认实现就是这样做的,因此在这里调用父类。

自定义重定向

从v0.6.0版本开始,我们添加了自定义重定向方法的功能。例如,如果会话令牌已过期,但用户仍然通过Laravel进行身份验证,我们可以用以下示例进行检查

<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;

use Auth;

class AppAzure extends Azure
{
    protected function redirect(Request $request)
    {
        if (Auth::user() !== null)
        {
            return $this->azure($request);
        }
        else
        {
            return parent::redirect($request);
        }
    }
}

不同的登录路由

从v0.4.0版本开始,我们添加了更改中间件中的$login_route的能力。基于扩展安装,在我们的AppAzure类中,我们可以简单地设置$login_route为任何值。例如

<?php

namespace App\Http\Middleware;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;

class AppAzure extends Azure
{
    protected $login_route = "/";
}

以上将$login_route设置为/或根目录。

获取/重写Azure路由

从v0.7.0版本开始,我们添加了获取Azure URL的能力。例如,假设我们想要修改Azure URL,使其将用户的电子邮件作为参数传递给Azure。基于扩展安装,在我们的AppAzure类中,我们可以这样做

<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;

use Auth;

class AppAzure extends Azure
{
    //we could overload this if we wanted too.
    public function getAzureUrl()
    {
        $url = $this->baseUrl . config('azure.tenant_id') . $this->route2 . "authorize?response_type=code&client_id=" . config('azure.client.id') . "&domain_hint=" . urlencode(config('azure.domain_hint')) . "&scope=" . urldecode(config('azure.scope'));

        return Route::has('azure.callback') ? $url . '&redirect_uri=' . urlencode(route('azure.callback')) : $url;
    }

    public function azure(Request $request)
    {
        $user = Auth::user();

        $away = $this->getAzureUrl();

        if ($user)
        {
            $away .= "&login_hint=" . $user->email;
        }

        return redirect()->away($away);
    }
}

在多租户应用程序中使用

如果所需的用例需要多租户应用程序,您只需在.env文件中提供common而不是租户ID即可。例如:AZURE_TENANT_ID=common

这通过将您的最终用户发送到Microsoft提供的通用登录路由来完成,从开发的角度来看,这看起来应该没有太大区别。应该知道,这种方法的潜在缺点已在MS Dev文档中提及

当单个租户应用程序验证令牌时,它会将令牌签名与元数据文档中的签名密钥进行比较。此测试允许它确保令牌中的发行者值与元数据文档中找到的值匹配。因为/common端点不对应于任何租户,也不是发行者,所以当您检查/common的元数据中的发行者值时,它有一个模板URL而不是实际值...

有关此信息的更多信息,请参阅此处

使用Laravel Azure Middleware进行测试

自v0.7.0版本起,我们通过调用actingAs为HTTP测试或使用Dusk的loginAs与Laravel测试进行集成。这假设我们在成功回调中使用Auth::login方法,如扩展安装中所示。在AppAzure类中无需进行任何操作,除非我们需要覆盖默认行为,如下所示

<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;

use petrsimunek\LaravelAzureMiddleware\Azure as Azure;

use Auth;

class AppAzure extends Azure
{
    //this is the default behavior
    //overwrite to meet your needs
    protected function handleTesting(Request $request, Closure $next)
    {
        $user = Auth::user();

        if (!isset($user))
        {
            return $this->redirect($request, $next);
        }

        return $this->handlecallback($request, $next, null, null);
    }
}

上述代码将调用类的重定向方法,如果它无法在Laravel的认证中找到用户。否则,上述代码将调用类的handlecallback方法。因此,测试可以检查是否发生了正确的重定向,或者handlecallback是否正常工作(默认情况下调用$next($request);)。

贡献

感谢您考虑为Laravel Azure Middleware做出贡献!为了鼓励积极的协作,我们鼓励提交pull请求,而不仅仅是问题报告。

如果您提交问题,问题应该包含标题和问题清晰的描述。您还应该包括尽可能多的相关信息和一个演示问题的代码示例。问题的目标是让您和其他人能够轻松地复现错误并开发解决方案。

许可证

Laravel Azure Middleware是开源软件,许可协议为MIT许可证