You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过OAuth2令牌从外部网站实现Drupal 8自动SSO登录/注册

嘿,我来帮你一步步搞定Drupal 8的这个SSO集成需求,我之前做过类似的场景,咱们拆解问题来解决:

1. 创建处理令牌的自定义路由(对应你的第一个需求)

首先得搞个自定义模块(比如命名为sso_auth),因为这种定制化的SSO逻辑没法靠现有模块完全搞定。步骤如下:

  • 在模块根目录创建routing.yml,定义一个接收令牌的路由:
sso_auth.login:
  path: '/sso/login'
  defaults:
    _controller: '\Drupal\sso_auth\Controller\SsoAuthController::login'
    _title: 'SSO Login'
  requirements:
    _access: 'TRUE'
  • 然后在src/Controller目录下创建控制器类SsoAuthController.php,这个类就是用来处理令牌请求的入口。
2. 解析令牌、自动创建/登录用户

在控制器的login方法里,按以下逻辑实现:

<?php

namespace Drupal\sso_auth\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\user\Entity\User;

class SsoAuthController extends ControllerBase {

  public function login() {
    // 1. 从URL获取令牌参数(假设令牌通过?token=xxx传递)
    $token = \Drupal::request()->query->get('token');
    if (!$token) {
      return $this->redirect('<front>', [], ['query' => ['error' => 'missing_token']]);
    }

    // 2. 验证令牌合法性!这一步非常关键,不能直接信任令牌内容
    // 这里根据你的外部OAuth2服务规则来,比如用JWT解析验证签名,或者调用外部接口验证
    // 示例:假设解析后得到外部uid、名称、邮箱等信息
    $token_data = $this->validateAndParseToken($token);
    if (!$token_data) {
      return $this->redirect('<front>', [], ['query' => ['error' => 'invalid_token']]);
    }
    $external_uid = $token_data['uid'];
    $external_name = $token_data['name'];
    $external_email = $token_data['email'] ?? $external_uid . '@your-domain.com';

    // 3. 检查本地用户是否存在(先给用户添加一个字段field_external_uid存储外部uid,避免和本地uid冲突)
    $existing_users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties([
      'field_external_uid' => $external_uid,
    ]);
    $user = reset($existing_users);

    // 4. 不存在则创建用户
    if (!$user) {
      $user = User::create([
        'name' => $external_name,
        'mail' => $external_email,
        'field_external_uid' => $external_uid,
        'status' => 1, // 直接激活用户
      ]);
      $user->save();
    }

    // 5. 自动登录用户
    user_login_finalize($user);

    // 6. 跳转到首页或用户个人页
    return new RedirectResponse(\Drupal\Core\Url::fromRoute('<front>')->toString());
  }

  // 这里实现你的令牌验证解析逻辑
  private function validateAndParseToken($token) {
    // 示例伪代码,根据实际OAuth2服务调整
    // 比如用JWT库解析:
    // $jwt = \Firebase\JWT\JWT::decode($token, $your_secret_key, ['HS256']);
    // return (array)$jwt;
    return ['uid' => 'external_123', 'name' => '张三', 'email' => 'zhangsan@example.com'];
  }
}

注意:令牌验证绝对不能省略,否则会有安全风险,一定要确保令牌是外部服务合法签发的。

3. 实现SSO登出

要实现两边同步登出,你可以通过钩子或者自定义登出逻辑来处理:

  • 方式一:用hook_user_logout钩子,在用户登出Drupal时,跳转到外部系统的登出页面:
<?php

/**
 * Implements hook_user_logout().
 */
function sso_auth_user_logout($account) {
  // 获取用户的外部uid
  $external_uid = $account->get('field_external_uid')->value;
  // 构造外部系统的登出URL,带上跳回Drupal的地址
  $external_logout_url = 'https://your-external-site.com/logout?redirect=' . urlencode(\Drupal\Core\Url::fromRoute('<front>')->toString());
  // 跳转到外部登出页面
  \Drupal::response()->setTargetUrl($external_logout_url);
}
  • 方式二:如果需要更定制化的登出流程,也可以自定义登出路由,替换默认的登出行为。

另外,关于你提到的External Authentication模块,它的文档确实比较匮乏,而且对于已经有令牌的场景,自定义代码反而更灵活可控,不用强行依赖它。

最后提醒几个关键点:

  • 令牌传输一定要用HTTPS,防止被窃取
  • 令牌的过期时间要在验证时检查,避免使用过期令牌
  • 用户字段的映射要根据你的令牌实际包含的字段调整,比如没有邮箱的话可以用外部uid拼接占位邮箱

内容的提问来源于stack exchange,提问作者sidikidis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:09:57