使用 Laravel 的 Azure Active Directory SSO

2024-03-03

我正在使用 azure Active Directory 进行 sso。我已经在 azure 上完成了设置并开始操作。我正在使用计量学/laravel-azure-ad-oauth (https://packagist.org/packages/metrogistics/laravel-azure-ad-oauth https://packagist.org/packages/metrogistics/laravel-azure-ad-oauth)在 laravel 上打包来做到这一点。但是,当我点击网址时http://localhost:8000/登录/微软 http://localhost:8000/login/microsoft,我被重定向到微软登录页面并给出错误消息。

我已将以下配置添加到 env 文件中,并执行了包所需的任何操作。

AZURE_AD_CLIENT_ID=XXXXXXXXXXXXXXXXXX(这是来自 azure 的应用程序 ID) AZURE_AD_CLIENT_SECRET=XXXXXXXXX(在 azure 上创建了新密钥)

我已经在网上搜索了两天,但找不到解决方案。我在这里缺少什么?

Thanks,


对于那些还在努力奋斗的人们Azure Active Directory SSO in Laravel。如果您愿意使用 SAML。 这是他们可以使用的存储库。

https://github.com/aacotroneo/laravel-saml2 https://github.com/aacotroneo/laravel-saml2

只要您在 Azure 门户上正确完成了 SSO 设置,它的使用就非常简单。

这是两步过程

步骤 1 - 在 Azure 门户上设置 SSO 项目


a) Go to Azure Active Directory进而Enterprise Application

b)添加新应用程序并选择Non-gallery Application

c) Click Set up single sign on然后点击SAML Box

d)编辑basic SAML configuration并添加以下内容

标识符(实体 ID) - https://my-laravel-website.com/saml2/aad/metadata https://my-laravel-website.com/saml2/aad/metadata

回复 URL(断言消费者服务 URL) - https://my-laravel-website.com/saml2/aad/acs https://my-laravel-website.com/saml2/aad/acs

(这些网址来自哪里,我将在Step 2。现在只需保存它即可。)

e)下载Federation Metadata XML from SAML Signing Certificate部分,在您的系统上

f)接下来将用户分配到当前的 SAML SSO 项目。

注意-如果您的帐户中不存在用户。然后你需要创建一个并分配一些角色(这是必要的).

这是设置步骤 1 的教程https://www.youtube.com/watch?v=xn_8Fm7S7y8 https://www.youtube.com/watch?v=xn_8Fm7S7y8

.

第 2 步 - 在项目中安装并配置 Laravel SAML 2 包


a) run composer require aacotroneo/laravel-saml2

b) run php artisan vendor:publish --provider="Aacotroneo\Saml2\Saml2ServiceProvider"

c)配置/saml2_settings.php

<?php

return $settings = array(

    /**
     * Array of IDP prefixes to be configured e.g. 'idpNames' => ['test1', 'test2', 'test3'],
     * Separate routes will be automatically registered for each IDP specified with IDP name as prefix
     * Separate config file saml2/<idpName>_idp_settings.php should be added & configured accordingly
     */
    'idpNames' => ['aad'],

    /**
     * If 'useRoutes' is set to true, the package defines five new routes for reach entry in idpNames:
     *
     *    Method | URI                                | Name
     *    -------|------------------------------------|------------------
     *    POST   | {routesPrefix}/{idpName}/acs       | saml_acs
     *    GET    | {routesPrefix}/{idpName}/login     | saml_login
     *    GET    | {routesPrefix}/{idpName}/logout    | saml_logout
     *    GET    | {routesPrefix}/{idpName}/metadata  | saml_metadata
     *    GET    | {routesPrefix}/{idpName}/sls       | saml_sls
     */
    'useRoutes' => true,

    /**
     * Optional, leave empty if you want the defined routes to be top level, i.e. "/{idpName}/*"
     */
    'routesPrefix' => 'saml2',

    /**
     * which middleware group to use for the saml routes
     * Laravel 5.2 will need a group which includes StartSession
     */
    'routesMiddleware' => ['saml'],

    /**
     * Indicates how the parameters will be
     * retrieved from the sls request for signature validation
     */
    'retrieveParametersFromServer' => false,

    /**
     * Where to redirect after logout
     */
    'logoutRoute' => '/login',

    /**
     * Where to redirect after login if no other option was provided
     */
    'loginRoute' => '/dashboard',

    /**
     * Where to redirect after login if no other option was provided
     */
    'errorRoute' => '/login',

    // If 'proxyVars' is True, then the Saml lib will trust proxy headers
    // e.g X-Forwarded-Proto / HTTP_X_FORWARDED_PROTO. This is useful if
    // your application is running behind a load balancer which terminates
    // SSL.
    'proxyVars' => true,

    /**
     * (Optional) Which class implements the route functions.
     * If commented out, defaults to this lib's controller (Aacotroneo\Saml2\Http\Controllers\Saml2Controller).
     * If you need to extend Saml2Controller (e.g. to override the `login()` function to pass
     * a `$returnTo` argument), this value allows you to pass your own controller, and have
     * it used in the routes definition.
     */
     'saml2_controller' => 'App\Http\Controllers\Auth\SAML2LoginController',
);

Note - Part d) of Step 1来自以下

d)创建一个新文件config/saml2/aad_idp_settings.php并复制内容config/saml2/test_idp_settings.php进去。改变$this_idp_env_id in aad_idp_settings.php to 'AAD'。所以最后的aad_idp_settings.php将如下所示。

<?php

// If you choose to use ENV vars to define these values, give this IdP its own env var names
// so you can define different values for each IdP, all starting with 'SAML2_'.$this_idp_env_id
$this_idp_env_id = 'AAD';

//This is variable is for simplesaml example only.
// For real IdP, you must set the url values in the 'idp' config to conform to the IdP's real urls.
$idp_host = env('SAML2_'.$this_idp_env_id.'_IDP_HOST', 'http://localhost:8000/simplesaml');

return $settings = array(

    /*****
     * One Login Settings
     */

    // If 'strict' is True, then the PHP Toolkit will reject unsigned
    // or unencrypted messages if it expects them signed or encrypted
    // Also will reject the messages if not strictly follow the SAML
    // standard: Destination, NameId, Conditions ... are validated too.
    'strict' => true, //@todo: make this depend on laravel config

    // Enable debug mode (to print errors)
    'debug' => env('APP_DEBUG', false),

    // Service Provider Data that we are deploying
    'sp' => array(

        // Specifies constraints on the name identifier to be used to
        // represent the requested subject.
        // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
        'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',

        // Usually x509cert and privateKey of the SP are provided by files placed at
        // the certs folder. But we can also provide them with the following parameters
        'x509cert' => env('SAML2_'.$this_idp_env_id.'_SP_x509',''),
        'privateKey' => env('SAML2_'.$this_idp_env_id.'_SP_PRIVATEKEY',''),

        // Identifier (URI) of the SP entity.
        // Leave blank to use the '{idpName}_metadata' route, e.g. 'test_metadata'.
        'entityId' => env('SAML2_'.$this_idp_env_id.'_SP_ENTITYID',''),

        // Specifies info about where and how the <AuthnResponse> message MUST be
        // returned to the requester, in this case our SP.
        'assertionConsumerService' => array(
            // URL Location where the <Response> from the IdP will be returned,
            // using HTTP-POST binding.
            // Leave blank to use the '{idpName}_acs' route, e.g. 'test_acs'
            'url' => '',
        ),
        // Specifies info about where and how the <Logout Response> message MUST be
        // returned to the requester, in this case our SP.
        // Remove this part to not include any URL Location in the metadata.
        'singleLogoutService' => array(
            // URL Location where the <Response> from the IdP will be returned,
            // using HTTP-Redirect binding.
            // Leave blank to use the '{idpName}_sls' route, e.g. 'test_sls'
            'url' => '',
        ),
    ),

    // Identity Provider Data that we want connect with our SP
    'idp' => array(
        // Identifier of the IdP entity  (must be a URI)
        'entityId' => env('SAML2_'.$this_idp_env_id.'_IDP_ENTITYID', $idp_host . '/saml2/idp/metadata.php'),
        // SSO endpoint info of the IdP. (Authentication Request protocol)
        'singleSignOnService' => array(
            // URL Target of the IdP where the SP will send the Authentication Request Message,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SSO_URL', $idp_host . '/saml2/idp/SSOService.php'),
        ),
        // SLO endpoint info of the IdP.
        'singleLogoutService' => array(
            // URL Location of the IdP where the SP will send the SLO Request,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SL_URL', $idp_host . '/saml2/idp/SingleLogoutService.php'),
        ),
        // Public x509 certificate of the IdP
        'x509cert' => env('SAML2_'.$this_idp_env_id.'_IDP_x509', 'MIID/TCCAuWgAwIBAgIJAI4R3WyjjmB1MA0GCS'),
        /*
         *  Instead of use the whole x509cert you can use a fingerprint
         *  (openssl x509 -noout -fingerprint -in "idp.crt" to generate it)
         */
        // 'certFingerprint' => '',
    ),



    /***
     *
     *  OneLogin advanced settings
     *
     *
     */
    // Security settings
    'security' => array(

        /** signatures and encryptions offered */

        // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
        // will be encrypted.
        'nameIdEncrypted' => false,

        // Indicates whether the <samlp:AuthnRequest> messages sent by this SP
        // will be signed.              [The Metadata of the SP will offer this info]
        'authnRequestsSigned' => false,

        // Indicates whether the <samlp:logoutRequest> messages sent by this SP
        // will be signed.
        'logoutRequestSigned' => false,

        // Indicates whether the <samlp:logoutResponse> messages sent by this SP
        // will be signed.
        'logoutResponseSigned' => false,

        /* Sign the Metadata
         False || True (use sp certs) || array (
                                                    keyFileName => 'metadata.key',
                                                    certFileName => 'metadata.crt'
                                                )
        */
        'signMetadata' => false,


        /** signatures and encryptions required **/

        // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
        // <samlp:LogoutResponse> elements received by this SP to be signed.
        'wantMessagesSigned' => false,

        // Indicates a requirement for the <saml:Assertion> elements received by
        // this SP to be signed.        [The Metadata of the SP will offer this info]
        'wantAssertionsSigned' => false,

        // Indicates a requirement for the NameID received by
        // this SP to be encrypted.
        'wantNameIdEncrypted' => false,

        // Authentication context.
        // Set to false and no AuthContext will be sent in the AuthNRequest,
        // Set true or don't present thi parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
        // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
        'requestedAuthnContext' => true,
    ),

    // Contact information template, it is recommended to suply a technical and support contacts
    'contactPerson' => array(
        'technical' => array(
            'givenName' => 'name',
            'emailAddress' => '[email protected] /cdn-cgi/l/email-protection'
        ),
        'support' => array(
            'givenName' => 'Support',
            'emailAddress' => '[email protected] /cdn-cgi/l/email-protection'
        ),
    ),

    // Organization information template, the info in en_US lang is recomended, add more if required
    'organization' => array(
        'en-US' => array(
            'name' => 'Name',
            'displayname' => 'Display Name',
            'url' => 'http://url'
        ),
    ),

/* Interoperable SAML 2.0 Web Browser SSO Profile [saml2int]   http://saml2int.org/profile/current

   'authnRequestsSigned' => false,    // SP SHOULD NOT sign the <samlp:AuthnRequest>,
                                      // MUST NOT assume that the IdP validates the sign
   'wantAssertionsSigned' => true,
   'wantAssertionsEncrypted' => true, // MUST be enabled if SSL/HTTPs is disabled
   'wantNameIdEncrypted' => false,
*/

);

e)现在我们需要放置以下 ENV 变量

SAML2_AAD_IDP_ENTITYID=
SAML2_AAD_IDP_SSO_URL=
SAML2_AAD_IDP_SL_URL=
SAML2_AAD_IDP_x509=

前 3 个环境变量的值将来自此处。

最后一个环境变量将来自以下内容

f) run php artisan make:provider SAML2ServiceProvider。这将创建一个文件app/Providers/SAML2ServiceProvider.php.

In the boot方法粘贴以下代码片段

Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (Saml2LoginEvent $event) {
            $messageId = $event->getSaml2Auth()->getLastMessageId();
            // Add your own code preventing reuse of a $messageId to stop replay attacks

            $user = $event->getSaml2User();
            $userData = [
                'id' => $user->getUserId(),
                'attributes' => $user->getAttributes(),
                'assertion' => $user->getRawSamlAssertion()
            ];

            $inputs = [
                'sso_user_id'  => $user->getUserId(),
                'username'     => self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),
                'email'        => self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),
                'first_name'   => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
                'last_name'    => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
                'password'     => Hash::make('anything'),
             ];

            $user = User::where('sso_user_id', $inputs['sso_user_id'])->where('email', $inputs['email'])->first();
            if(!$user){
                $res = PortalUser::store($inputs);
                if($res['status'] == 'success'){
                    $user  = $res['data'];
                    Auth::guard('web')->login($user);
                }else{
                    Log::info('SAML USER Error '.$res['messages']);
                }
            }else{
                Auth::guard('web')->login($user);
            }

        });

最后在中注册该提供商提供者的数组config/app.php.

。 测试 SAML AAD SSO


Go to https://[your-site-url]/saml2/aad/login

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Laravel 的 Azure Active Directory SSO 的相关文章

  • 仅为两个控制器分配不同的域

    我使用的是旧的 Yii v1 我只需要为两个控制器分配不同的域 所以我有一堆控制器 HomeController php CategoryController php GuestbookController php ShopControll
  • 如何禁用 Yii2 中的按钮

    我正在尝试禁用创建项目 Button当用户未登录时 该按钮将Hide or disable 这是我的条件 p p 它正在工作 但是 当用户登
  • Paypal PDT交易ID有效期

    当我尝试使用交易 ID 检索付款信息时 我从 paypal PDT 收到错误 4003 虽然我这里有一个类似的线程 贝宝 PDT 错误 4003 https stackoverflow com questions 8521800 paypa
  • 如何同时使用 Google Drive API 和 Chrome Web Payments 许可 API

    更新以澄清问题 在尝试在我们的测试应用程序中使用 google Drive 示例应用程序 Dr edit for php 时 该应用程序已经成功实现了许可 API https developers google com chrome web
  • 在 PHP / MySQL 中处理未读帖子

    对于个人项目 我需要使用 PHP 和 MySQL 构建一个论坛 我不可能使用已经构建的论坛包 例如phpBB 我目前正在研究构建此类应用程序所需的逻辑 但这已经是漫长的一天了 我正在努力解决为用户处理未读帖子的概念 我的一个解决方案是有一个
  • 回退到正则表达式中字符串的开头

    是否可以让正则表达式退回到字符串的开头并再次开始匹配 这就是我问的原因 给定下面的字符串 我想捕获子字符串black red blue and green按照该顺序 无论主题字符串中出现的顺序如何 并且仅当所有子字符串都存在于主题字符串中时
  • 定义根路径

    我正在寻找一种将配置变量定义为我的网站的根路径的方法 定义这个的最好方法是什么 我正在使用 Codeigniter config root path 这是我的 config 文件夹中的 site config 文件 dev dev appl
  • strpos 0==false 问题?

    我使用 strpos 来查找一个字符串在另一个字符串中的位置 我首先检查是否在那里找到了该字符串 这是我的台词 if strpos grafik data ss1 lt gt false strpos grafik data ss2 lt
  • HTML/PHP 中的 POST 和 GET 有什么区别[重复]

    这个问题在这里已经有答案了 我正在编写一个 PHP 脚本 但我似乎无法真正让它工作 我正在测试基础知识 但我不太明白 GET 和 POST 意味着什么 有什么区别 我在网上看到的所有定义对我来说没有多大意义 到目前为止我编写的代码 但由于我
  • Javascript crc32 函数和 PHP crc32 与 UTF8 不匹配

    我一直在尝试从 PHP 获取 crc32 函数来匹配 javascript 生成的结果 我已经使用了 4 个不同的 javascript crc32 库 1 http www webtoolkit info javascript crc32
  • 最佳实践:在 PHP 中导入 mySQL 文件;分割查询

    我遇到了一种情况 我必须更新共享托管提供商上的网站 该网站有一个 CMS 使用 FTP 上传 CMS 文件非常简单 我还必须导入一个大的 相对于 PHP 脚本的范围 数据库文件 未压缩时大约 2 3 MB Mysql 已关闭 无法从外部访问
  • 使用 Composer CLI 将数据添加到额外属性

    根据文档extra的财产composer json 架构 https getcomposer org doc 04 schema md extra 允许设置 供脚本使用的任意额外数据 出于脚本目的 如果可以将数据添加到extra通过命令行属
  • 随机字体颜色

    我需要用 2 或 3 种随机颜色为文本着色 我如何在 PHP 或 JavaScript 中执行此操作 color str pad sprintf x x x rand 0 255 rand 0 255 rand 0 255 6 rand 0
  • 如何通过单击按钮调用 PHP 函数

    我创建了一个名为的页面functioncalling php包含两个按钮 Submit and Insert 我想测试单击按钮时执行哪个函数 我希望输出出现在同一页面上 因此 我创建了两个函数 每个按钮一个
  • Bot 在本地计算机上的 Bot Framework Emulator 中运行,但在部署到 Microsoft Azure 后无法运行 - HTTP 状态代码 NotFound

    现在 我正在测试启动机器人项目所需的步骤2019 年虚拟演播室社区 测试机器人机器人框架模拟器 V4 然后将该机器人部署到 Microsoft Azure 现在 我正在测试 Virtual Studio Community 2019 中提供
  • 从数据库结果生成多维数组的递归函数

    我正在编写一个函数 它接受页面 类别数组 来自平面数据库结果 并根据父 ID 生成嵌套页面 类别项目数组 我想递归地执行此操作 以便可以完成任何级别的嵌套 例如 我在一个查询中获取所有页面 这就是数据库表的样子 id parent id t
  • 如何将 ZF2 单元/应用程序模块测试合并到单个调用中?

    我遵循将测试存储在模块中的 ZF2 约定 并且当从每个模块内运行测试时一切正常 我想做的是有一个根级别的 phpunit xml 来调用各个模块测试并将它们合并以生成代码覆盖率数据和其他指标 问题是每个单独的测试套件都是在模块化 phpun
  • 如何创建一个每次调用公共方法时都会调用的方法?

    如何创建一个每次调用公共方法时都会调用的方法 您也可以说这是一个后方法调用挂钩 我当前的代码
  • 如何禁用vuejs中的按钮

    我想在填写表单时禁用该按钮 当所有输入都填满后 将使用 vuejs 和 laravel 框架启用按钮 我尝试通过简单地禁用按钮来实现这一点
  • PHP MySQLi 多次插入

    我想知道准备好的语句是否与具有多个值的普通 mysql query 一样工作 INSERT INTO table a b VALUES a b c d VS sql db gt prepare INSERT INTO table a b V

随机推荐