单点登录(SSO)Laravel

14

我有三个不同的Laravel网站,我希望用户在其中一个网站登录后,可以自动登录到另外两个网站。

例如,如果您在stackoverflow上登录,然后打开stackexchange,您将使用StackOverflow帐户登录。

我尝试了许多软件包,但它们都以无限异常结束或根本不起作用。大多数软件包基于SAML,我不知道为什么它们不适用于我?我不知道我错过了什么?是否有任何配置可以使其正常工作?我正在使用laravel 5.6。所有应用程序都在同一台服务器上。

我尝试了很多基于SAML、OpenID和共享会话的解决方案,但它们都没有与我一起工作。我不知道我是否漏掉了什么东西。这是我尝试的最后一个示例,但它并没有起作用。

这是我的代码

SITE A

$site_b = 'http://s_sesstion_2.test/';
Route::get('/', function (Request $request) use ($site_b) {
    $session_id = Session::getId();
    try {
        $http = new Client();
        $response = $http->post($site_b . 'api/sessions/server', [
            'form_params' => [
                'session_id' => $session_id,
            ],
            'headers' => [
                'Accept' => 'application/json',
            ]
        ]);
    } catch (Exception $e) {
        dd($e->getMessage());
    }
    return view('welcome');
});

SITE B (路由/api.php)

    Route::post('/sessions/server', function (Request $request) {
    Storage::disk('local')->put('file.txt', $request->get('session_id'));
});

SITE B (路由/ web.php)

    Route::get('/', function () {
    $session_id = Storage::disk('local')->get('file.txt');
    Session::setId($session_id);
    Session::start();
    //return Session::getId();// will return the same session id
    return \auth()->user();//this should return the auth user but it did not!!
});

我想要的就是在A网站登录,然后打开B网站时自动登录。 我接受任何实现此目的的解决方案


@Kyslik是的,它们共享同一个数据库。 - Moauya Meghari
你需要尝试解决方案并展示你所尝试的内容。SSO是一个非常广泛的主题,有许多种解决方法,我们不能仅仅猜测哪种方法最适合你的情况。 - apokryfos
2
如果您不分享您尝试过的实际代码,我们就无法知道为什么事情没有奏效。 - apokryfos
这个解决方案可能会有所帮助。 - Gunnrryy
显示剩余3条评论
2个回答

22

我实现了一种不使用SAML的单点登录(SSO)解决方案,我将在此分享我的解决方案,希望能帮到大家。

单点登录

auth.domain是主认证服务器,其他应用程序分别在不同的域中 app1.domain, app2.domain, ...

每个用户都与SSO令牌相关联,这些令牌具有非常短暂的过期时间。所有身份验证过程(登录、重置密码、注册等)均仅在auth.domain 应用程序中进行。

当用户访问任何应用程序时,例如:app-1.domain:

  1. 重定向用户到 auth.domain/login
  2. 如果用户之前已经登录过系统,则继续执行第6步
  3. 显示登录表单,等待有效输入。
  4. 生成一个新的SSO令牌,其过期时间小于3分钟。
  5. auth.domain的“记住我”cookie附加到响应中。
  6. 返回一个重定向响应到 app-1.domain/sso/{sso_token}
  7. app-1.domain应用程序读取数据库,如果SSO令牌有效且未过期,则找到与该令牌相关联的用户。
  8. app-1.domainAuth::login($user)方法对在上一步中找到的用户进行身份验证。
  • app-1.domain 从数据库中清除接收到的SSO令牌
  • 完成此步骤后,用户已通过app-1.domain进行身份验证。

    会话共享

    所有共享会话变量都应保存到数据库中。我实现了一个新的会话驱动程序:

    • 保留共享会话变量名称列表
    • 在读写会话时,请检查会话变量的名称。如果该名称是先前列出的列表之一,则从数据库中读取/写入该值。否则,使用每个应用程序自己的私有会话。

    1
    不错的解决方案!你是如何处理注销的? - Philipp Nies
    当用户注销时,我将重定向他们到 auth.domain/logout 来清除共同的会话,然后再将他/她重定向回原始网站。 - Hieu Le
    嗨@HieuLe,我想知道在步骤4中,这是否意味着每当3分钟令牌过期时,我们都会遇到每个301重定向?或者我们可以在http / ajax请求中刷新令牌? - Mavichow
    我一直在尝试使用Auth::login($user),但是我得到了BadMethodCallException: Method Illuminate\Auth\RequestGuard::loginUsingId does not exist的错误,请看一下这个链接https://stackoverflow.com/questions/66465177/laravel-6-how-to-autologin-user-in-a-different-laravel-application-without-pass - PHP User

    1
    如果您的两个应用程序共享相同的数据库,则可以按照以下方法进行操作:
    -> 在您的数据库中,创建一个默认会话ID,最初将其标记为false -> 现在,只要用户登录任何一个站点,就生成一个新的哈希值并用它替换默认值。

    可选

    -> 您还可以将哈希保存在浏览器本地存储中,哈希作为键,null作为值。


    -> 现在当用户登录/切换到任何站点时,检查哈希值 -> 如果哈希值与默认值匹配,则显示登录页面,否则显示个人资料页面。


    如果您正在使用通用数据库进行登录,则我的答案仅适用,否则您需要进行映射。


    或者您可以使用cookie来存储哈希值,并且可以在跨域中访问它们。 可以在 跨域Cookie 找到示例。 作者:@ludovic


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接