rootinc / laravel-azure-middleware
Azure 中间件认证
Requires
- php: >=5.6.4
- guzzlehttp/guzzle: >=6.2
- laravel/framework: >=5.4.0
- microsoft/microsoft-graph: ^1.5
README
为 Laravel 应用提供 Azure 认证中间件。如果您喜欢这个,请查看 Laravel Saml 中间件
常规安装
composer require rootinc/laravel-azure-middleware
- 运行
php artisan vendor:publish --provider="RootInc\LaravelAzureMiddleware\AzureServiceProvider"
将配置文件安装到config/azure.php
- 在我们的路由文件夹中(通常是
web.php
),添加
Route::get('/login/azure', '\RootInc\LaravelAzureMiddleware\Azure@azure') ->name('azure.login'); Route::get('/login/azurecallback', '\RootInc\LaravelAzureMiddleware\Azure@azurecallback') ->name('azure.callback');
注意:仅当在门户中配置
redirect_uri
时需要路由名称。
- 在我们的
App\Http\Kernel.php
中添加'azure' => \RootInc\LaravelAzureMiddleware\Azure::class,
很可能添加到$routeMiddleware
数组中。 - 在我们的
.env
中添加AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET 和 AZURE_RESOURCE
。我们可以在https://portal.azure.com/ 获取这些值/了解更多信息(提示:AZURE_RESOURCE 应为 https://graph.microsoft.com) - 截至 0.8.0 版本,我们添加了
AZURE_SCOPE
,这是用于请求的权限。我们可以在https://docs.microsoft.com/en-us/graph/api/resources/users?view=graph-rest-1.0 了解更多 - 我们还添加了一个可选的
AZURE_DOMAIN_HINT
,可以帮助用户知道应该使用哪个电子邮件地址登录。更多信息请参阅https://azure.microsoft.com/en-us/updates/app-service-auth-and-azure-ad-domain-hints/ - 在我们的应用上https://portal.azure.com/,将
reply url
指向/login/azurecallback
路由,使用完整的 URL(例如:http://thewebsite.com/login/azurecallback)。 - 将
azure
中间件添加到任何需要受保护的路由组中,并享受 🎉 - 如果您需要自定义回调,请参阅扩展安装。
注意:
您可能需要为(遗留的)Azure Active Directory Graph 添加权限截至 0.8.0 版本,我们使用 Azure 登录 API 的 v2,这允许我们传递作用域或我们想要使用的权限。
路由
Route::get('/login/azure', '\RootInc\LaravelAzureMiddleware\Azure@azure')->name('azure.login');
第一个参数可以是您想要路由 Azure 登录的任何地方。按需更改。
Route::get('/login/azurecallback', '\RootInc\LaravelAzureMiddleware\Azure@azurecallback')->name('azure.callback');
第一个参数可以是您想要在回调后路由的任何内容。按需更改。
Route::get('/logout/azure', '\RootInc\LaravelAzureMiddleware\Azure@azurelogout')->name('azure.logout);
第一个参数可以是您想要在回调后路由的任何内容。按需更改。
注意:仅当在门户中配置
redirect_uri
时需要路由名称。
前端
最好在登录网页上有一个 Office 365 按钮,该按钮路由到 route('azure.login')
。这可以是一个像这样的锚标签 <a href="{{ route('azure.login') }}" class="officeButton"></a>
扩展安装
默认实现允许您登录用户。但是,假设我们想要将此用户存储到数据库中,以及使用 Laravel Auth 登录用户。我们建议从 Azure 类扩展两个回调,即 success
和 fail
。以下提供有关如何扩展 Root Laravel Azure 中间件库的信息
- 要开始使用(假设我们已经遵循了正常安装说明),在
App\Http\Middleware
文件夹中创建一个名为AppAzure.php
的文件。您可以通过artisan
或手动完成此操作。 - 将以下内容作为该文件的起始点
<?php namespace App\Http\Middleware; use Illuminate\Http\Request; use RootInc\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,或者/
,因此我们在父类中调用。您可以根据需要不扩展默认实现,并将重定向到其他地方。
- 我们需要将路由更新为以下内容
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');
- 最后,更新
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 RootInc\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 RootInc\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 RootInc\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 RootInc\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 RootInc\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做出贡献!为了鼓励积极的协作,我们鼓励提交拉取请求,而不仅仅是问题报告。
如果您提交问题报告,问题报告应包含标题和问题的清晰描述。您还应包括尽可能多的相关信息和一个展示问题的代码示例。问题报告的目标是让您和其他人能够轻松地复现错误并开发解决方案。
许可协议
Laravel Azure Middleware是开源软件,遵循MIT许可协议。