【问题标题】:Unable to make Google OAuth2 work on CakePHP 3 app无法使 Google OAuth2 在 CakePHP 3 应用程序上运行
【发布时间】:2017-07-23 02:47:17
【问题描述】:

首先,感谢任何愿意和我一起研究这个问题的人。让我说我是一个 CakePHP 初学者。虽然我的网站是功能性的,但它相对简单,因此我没有从开发它的框架中获得太多的知识。比方说,我是一个基本用户,有一个不太基本的问题......!

所以,我目前正在使用 AngularJS 和 CakePHP 3 开发一个网站。CakePHP 部分是一个 REST API,当然还有网站的客户端 Angular。

某些页面只能由注册/登录的用户访问,或者至少是电子邮件与@mydomain.com 匹配的用户(然后应该注册)。

最初,API/站点被设计为通过 HTTP 基本身份验证来处理这个问题,但两天前我被要求通过 Google OAuth2 身份验证来处理它。

所以我试着环顾四周,是否有人在 CakePHP3 上做过,没有插件(有人向我提到 CakeDC/users 插件,但文档太差了,我没有去那里......) .我找到了这些:

http://caketuts.key-conseil.fr/index.php/2015/05/22/integrer-lapi-oauth2-de-google-avec-cakephp-v3/(法语,抱歉,但代码很清楚)

http://blog.jainsiddharth21.com/2013/04/29/login-with-google-in-cakephp/(这是可以理解的,但不是我真正选择的做法,但仍然有用且接近我的代码)

虽然我的代码几乎 90% 都像第一个链接,但我似乎无法让身份验证按预期的方式工作。

这是我的代码:

AppController.php:

public function initialize() {
    parent::initialize();

    $this->loadComponent('RequestHandler');
    $this->loadComponent('Flash');

    $this->loadComponent('Auth', [
        'loginAction' => [
            'controller' => 'Users',
            'action' => 'googlelogin',
        ],
        'authenticate' => [
            'Form' => [
                'fields' => [
                    'username' => 'email',
                    'password' => 'password'
                ]
            ]
        ],
        'authError' => __("You don't have rights for this page"),
        'authorize' => ['Controller'],
        'unauthorizedRedirect' => [
            'controller' => 'Users',
            'action' => 'forbidden'
        ],
        'loginRedirect' => [
            'controller' => 'myHomePage',
        ],
        'logoutRedirect' => [
            'controller' => 'Users',
            'action' => 'googlelogin'
        ]
    ]);
}

UsersController.php

public function googlelogin() {

    $client = new Google_Client();
    $client->setClientId(GOOGLE_OAUTH_CLIENT_ID);
    $client->setClientSecret(GOOGLE_OAUTH_CLIENT_SECRET);
    $client->setRedirectUri(GOOGLE_OAUTH_REDIRECT_URI);

    $client->setScopes(array(
        "https://www.googleapis.com/auth/userinfo.profile",
        'https://www.googleapis.com/auth/userinfo.email'
    ));
    $url = $client->createAuthUrl();
    $this->redirect($url);
}

public function confirmLogin() {
    $client = new Google_Client();
    $client->setClientId(GOOGLE_OAUTH_CLIENT_ID);
    $client->setClientSecret(GOOGLE_OAUTH_CLIENT_SECRET);
    $client->setRedirectUri(GOOGLE_OAUTH_REDIRECT_URI);

    $client->setScopes(array(
        "https://www.googleapis.com/auth/userinfo.profile",
        'https://www.googleapis.com/auth/userinfo.email'
    ));
    $client->setApprovalPrompt('auto');

    if (isset($this->request->query['code'])) {
        $client->authenticate($this->request->query['code']);
        $this->request->Session()->write('access_token', $client->getAccessToken());
    }

    if ($this->request->Session()->check('access_token') && ($this->request->Session()->read('access_token'))) {
        $client->setAccessToken($this->request->Session()->read('access_token'));
    }

    if ($client->getAccessToken()) {
        $this->request->Session()->write('access_token', $client->getAccessToken());
        $oauth2 = new Google_Service_Oauth2($client);
        $user = $oauth2->userinfo->get();
        try {
            if (!empty($user)) {
                if (preg_match("/(@mydomain\.com)$/", $user['email'])) {
                        $result = $this->Users->find('all')
                            ->where(['email' => $user['email']])
                            ->first();
                    if ($result) {
                        $this->Auth->setUser($result->toArray());
                        $this->redirect($this->Auth->redirectUrl());
                    } else {

                        $data = array();
                        $data['email'] = $user['email'];
                        $data['first_name'] = $user['givenName'];
                        $data['last_name'] = $user['familyName'];
                        $data['socialId'] = $user['id'];
                        //$data matches my Users table

                        $entity = $this->Users->newEntity($data);
                        if ($this->Users->save($entity)) {
                            $data['id'] = $entity->id;
                            $this->Auth->setUser($data);
                            $this->redirect($this->Auth->redirectUrl());
                        } else {
                            $this->Flash->set('Logging error');
                            $this->redirect(['action' => 'login']);
                        }
                    }
                } else {
                    $this->Flash->set('Forbidden');
                    $this->redirect(['action' => 'login']);
                }
            } else {
                $this->Flash->set('Google infos not found');
                $this->redirect(['action' => 'login']);
            }
        } catch (\Exception $e) {
            $this->Flash->set('Google error');
            return $this->redirect(['action' => 'login']);
        }
    }
}

我还在文件中添加了以下几行

paths.php

define('GOOGLE_OAUTH_CLIENT_ID', 'My_client_id');
define('GOOGLE_OAUTH_CLIENT_SECRET', 'My_client_secret');
define('GOOGLE_OAUTH_REDIRECT_URI', 'mylinkto/confirmLogin');

在 Chrome 的调试工具中,似乎使用有效代码作为查询参数调用了 confimLogin(顺便说一下两次),然后调用了 googlelogin。所以我每次都会出现在日志页面上......

我觉得这里一定有我遗漏的东西。有人有什么主意吗? (谢谢!)

【问题讨论】:

    标签: php angularjs cakephp oauth-2.0 google-oauth


    【解决方案1】:

    您应该在 Auth 组件中允许您的登录方法,以便对这些方法的操作不会再次重定向到 googlelogin 方法

    $this->Auth->allow(['googlelogin','confirmLogin']);
    

    【讨论】:

    • 所以我尝试了,将它添加到 AppController 的初始化方法和/或我的 UsersController 中的 beforeFilter 中,但没有改变。在confirmLogin 之后仍然调用googlelogin。我做错了吗?
    • 发现问题! allow 参数需要是一个数组 :) 感谢您的帮助!
    【解决方案2】:

    针对您对我们文档的评论,我们添加了关于 how to configure CakeDC/Users to use Google login in CakePHP 的详细分步教程:

    1. 使用 composer 安装 CakeDC 用户插件和所需的 oauth2 提供程序

    为了能够在 Google 仪表板中配置回调,您需要为您的应用程序创建一个虚拟主机。您不需要有效的域名,您可以使用“mydomain.dev”之类的名称,但 Google 需要域名(没有 localhost)。

    composer require cakedc/users:@stable 
    composer require league/oauth2-google:@stable
    
    1. 从你的 bootstrap.php 文件中加载它

      插件::load('CakeDC/Users', ['routes' => true, 'bootstrap' => true]);

    2. 运行迁移以添加 2 个新表:“users”和“social_accounts”

    bin/cake 迁移 migrate -p CakeDC/Users
    1. 在你的 src/Controller/AppController.php 中加载组件

      公共函数初始化() { 父::初始化(); // // ... // $this->loadComponent('CakeDC/Users.UsersAuth'); }

    2. 创建一个新的 Google 应用程序

    3. 获得客户端 ID 和客户端密码字符串后,在 /config/users.php 下添加以下配置文件,并粘贴您的客户端 ID 和密码。粘贴前修剪代码中的所有空格。

      // /config/users.php 文件内容 $配置 = [ 'Users.Social.login' => 真, 'OAuth.providers.google.options.clientId' => 'CLIENT_ID_HERE', 'OAuth.providers.google.options.clientSecret' => 'SECRET_HERE', ];

      返回 $config;

    4. 修改您的 bootstrap.php 文件以确保以这种方式加载配置文件

      配置::write('Users.config', ['users']); //在 Plugin::load('CakeDC/Users... 之前添加这一行 Plugin::load('CakeDC/Users', ['routes' => true, 'bootstrap' => true]);

    此文件将覆盖插件中存在的任何配置键,您可以在此处检查配置选项配置。

    完成!

    现在您可以前往登录页面并点击“使用 Google 注册”。

    【讨论】:

    • 太好了!肯定会在我的下一个项目中尝试,谢谢。这也可能会帮助许多其他人。
    • 很好,但是页面上的登录链接是什么?我可以在插件中看到它如何链接到它?
    • 我想我错过了进入插件文件夹的代码,似乎composer没有生成它,有github链接可以下载吗?谢谢
    • @gabrielkolbe 我们已经使用插件设置创建了一个示例 repo,还请注意这个答案是旧的,我们已经升级了插件以使用最新的 CakePHP 4 版本和最佳实践github.com/CakeDC/users-example/tree/9.next
    • 我已经安装了这个,但每次我回到我的网站时都需要重新登录。会话长度是否基于 users.php 中的“令牌”变量?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 2017-05-20
    • 2018-12-26
    相关资源
    最近更新 更多