NextCloud集成Oauth2单点登录笔记

如题

一、安装Social login插件

查看官网资料,不再赘述。

二、配置Social login插件

系统管理员账号登录后,先点击Setting,进入系统设置,后点击Social login,进入配置界面。

博主配置后的样例如下:

配置总结如下:

  • 允许自动创建新用户;
  • 允许已注册的用户采用Social login,在个性化设置界面,手动链接下方的Provider;
  • 若email地址已存在,则不允许创建新用户;
  • 用户每次登陆时,均更新用户信息;
  • 若新用户采用Social login登陆,则自动创建用户,且分配到Default Group;

配置完成后,经过测试可以实现登录、登出功能。

三、常见问题

3.1 Social login登录后,未使用已存在账户,而是新建了一个账户,如何解决?

Social login插件默认会使用Internal Name-identifier创建新用户。例如博主的已有用户名是Claves,若配置的Internal Name为QQ,则系统会默认创建一个登录名为QQ-Claves的新用户。且无法通过配置纠正此问题。

若实在想解决此问题,那方法就是修改代码。

修改lib\Controller\LoginController.php的private function auth($class, array $config, $provider, $providerType)函数。

修改:

$uid = $provider.'-'.$profileId;

$uid = $profileId;

即可解决该问题。

3.2 配置Oauth2配置后,登录始终报错如何解决?

由于Social login未提供属性映射功能,因为Oauth2 Provider的/getUserInfo 接口返回的属性名可能和Social login默认不一致。

想解决此方法,要么更改Social login插件代码,要么更改Oauth2 Provider配置。

Social login获取UserInfo 代码如下:

 public function getUserProfile()
    {
        $profileFields = $this->strToArray($this->config->get('profile_fields'));
        $profileUrl = $this->config->get('endpoints')['profile_url'];

        if (count($profileFields) > 0) {
            $profileUrl .= (strpos($profileUrl, '?') !== false ? '&' : '?') . 'fields=' . implode(',', $profileFields);
        }

        $response = $this->apiRequest($profileUrl);
        if (!isset($response->identifier) && isset($response->id)) {
            $response->identifier = $response->id;
        }
        if (!isset($response->identifier) && isset($response->data->id)) {
            $response->identifier = $response->data->id;
        }
        if (!isset($response->identifier) && isset($response->user_id)) {
            $response->identifier = $response->user_id;
        }

        $data = new Data\Collection($response);

        if (!$data->exists('identifier')) {
            throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
        }

        $userProfile = new User\Profile();
        foreach ($data->toArray() as $key => $value) {
            if ($key !== 'data' && property_exists($userProfile, $key)) {
                $userProfile->$key = $value;
            }
        }

        if (null !== $groups = $this->getGroups($data)) {
            $userProfile->data['groups'] = $groups;
        }
        if ($groupMapping = $this->config->get('group_mapping')) {
            $userProfile->data['group_mapping'] = $groupMapping;
        }

        return $userProfile;
    }

可以看到用户的唯一性标识字段仅支持identifier,id,user_id,不支持username等字段,因此需要统一。

 private function login($uid, Profile $profile, $newGroupPrefix = '')
    {
        $user = $this->userManager->get($uid);
        if (null === $user) {
            $connectedUid = $this->socialConnect->findUID($uid);
            $user = $this->userManager->get($connectedUid);
        }
        if ($this->userSession->isLoggedIn()) {
            if (!$this->config->getAppValue($this->appName, 'allow_login_connect')) {
                throw new LoginException($this->l->t('Social login connect is disabled'));
            }
            if (null !== $user) {
                throw new LoginException($this->l->t('This account already connected'));
            }
            $currentUid = $this->userSession->getUser()->getUID();
            $this->socialConnect->connectLogin($currentUid, $uid);
            return new RedirectResponse($this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section'=>'sociallogin']));
        }

        if ($this->config->getAppValue($this->appName, 'restrict_users_wo_mapped_groups') && isset($profile->data['group_mapping'])) {
            $groups = isset($profile->data['groups']) ? $profile->data['groups'] : [];
            $mappedGroups = array_intersect($groups, array_keys($profile->data['group_mapping']));
            if (!$mappedGroups) {
                throw new LoginException($this->l->t('Your user group is not allowed to login, please contact support'));
            }
        }

        $updateUserProfile = $this->config->getAppValue($this->appName, 'update_profile_on_login');

        if (null === $user) {
            if ($this->config->getAppValue($this->appName, 'disable_registration')) {
                throw new LoginException($this->l->t('Auto creating new users is disabled'));
            }
            if (
                $profile->email && $this->config->getAppValue($this->appName, 'prevent_create_email_exists')
                && count($this->userManager->getByEmail($profile->email)) !== 0
            ) {
                throw new LoginException($this->l->t('Email already registered'));
            }
            $password = substr(base64_encode(random_bytes(64)), 0, 30);
            $user = $this->userManager->createUser($uid, $password);

            if ($this->config->getAppValue($this->appName, 'create_disabled_users')) {
                $user->setEnabled(false);
            }

            $this->config->setUserValue($uid, $this->appName, 'disable_password_confirmation', 1);
            $updateUserProfile = true;

            if (!$this->config->getAppValue($this->appName, 'disable_notify_admins')) {
                $this->notifyAdmins($uid, $profile->displayName ?: $profile->identifier, $profile->data['default_group']);
            }
        }

        if ($updateUserProfile) {
            $user->setDisplayName($profile->displayName ?: $profile->identifier);
            $user->setEMailAddress((string)$profile->email);

            if ($profile->photoURL) {
                $curl = new Curl();
                try {
                    $photo = $curl->request($profile->photoURL);
                    $avatar = $this->avatarManager->getAvatar($uid);
                    $avatar->set($photo);
                } catch (\Exception $e) {}
            }

            if (isset($profile->data['groups']) && is_array($profile->data['groups'])) {
                $groupNames = $profile->data['groups'];
                $groupMapping = isset($profile->data['group_mapping']) ? $profile->data['group_mapping'] : null;
                $userGroups = $this->groupManager->getUserGroups($user);
                $autoCreateGroups = $this->config->getAppValue($this->appName, 'auto_create_groups');
                $syncGroupNames = [];

                foreach ($groupNames as $k => $v) {
                    if ($groupMapping && isset($groupMapping[$v])) {
                        $syncGroupNames[] = $groupMapping[$v];
                    }
                    if ($autoCreateGroups) {
                        $syncGroupNames[] = $newGroupPrefix.$v;
                    }
                }

                if (!$this->config->getAppValue($this->appName, 'no_prune_user_groups')) {
                    foreach ($userGroups as $group) {
                        if (!in_array($group->getGID(), $syncGroupNames)) {
                            $group->removeUser($user);
                        }
                    }
                }

                foreach ($syncGroupNames as $groupName) {
                    if ($group = $this->groupManager->createGroup($groupName)) {
                        $group->addUser($user);
                    }
                }

            }

            $defaultGroup = $profile->data['default_group'];
            if ($defaultGroup && $group = $this->groupManager->get($defaultGroup)) {
                $group->addUser($user);
            }
        }


        $this->userSession->completeLogin($user, ['loginName' => $user->getUID(), 'password' => '']);
        $this->userSession->createSessionToken($this->request, $user->getUID(), $user->getUID());

        if ($redirectUrl = $this->session->get('login_redirect_url')) {
            return new RedirectResponse($redirectUrl);
        }

        $this->session->set('last-password-confirm', time());

        return new RedirectResponse($this->urlGenerator->getAbsoluteURL('/'));
    }

通过以上代码可知,用户名只支持displayName字段,不支持常规的nickName,因此也需要适配统一。

分享到:更多 ()