duanma8207 2016-09-30 14:37
浏览 76
已采纳

无法让Google OAuth2在CakePHP 3应用上运行

First of all, thanks to anyone who will look into this with me. Let me just say that I am a CakePHP beginner. Although my website is functional, it is relatively simple thus I did not gain much knowledge of the framework from developing it. Let's say, I'm a basic user with a less basic problem...!

So, I'm currently developing a website with AngularJS and CakePHP 3. The CakePHP part is a REST API, and of course, the Angular, the client side of the website.

Some of the pages should only be accessed by registered/logged in users, or at least users which email matches @mydomain.com (who then should be registered).

At fisrt, the API/site were designed to deal with this through HTTP Basic authentication but two days ago I got asked to deal with it through a Google OAuth2 Authentication.

So I've tried looking around if anyone had done that on CakePHP3 yet, without a plugin (someone mentioned to me the CakeDC/users plugin, but the documentation is so poor that I didn't go there...). I found these :

http://caketuts.key-conseil.fr/index.php/2015/05/22/integrer-lapi-oauth2-de-google-avec-cakephp-v3/ (in French, sorry, but the code is pretty clear)

http://blog.jainsiddharth21.com/2013/04/29/login-with-google-in-cakephp/ (which is understandable but not really what I chose to do, but still usefull and close to my code)

Although my code is pretty much 90% like this first link, I can't seem to get the Authentication working the way it is supposed to.

Here is my code :

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']);
        }
    }
}

I also added the following lines to the file

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');

In Chrome's debugging tool, it seems that confimLogin is called (twice by the way) with a valid code as query parameter, and then googlelogin is called. So I end up on the log page every time...

I feel like there must be something I'm missing here. Does anyone have any idea? (Thanks!)

  • 写回答

2条回答 默认 最新

  • douhuifen9942 2016-10-01 05:49
    关注

    You should allow your login method in Auth component so that action to these method not get redirected again to googlelogin method

    $this->Auth->allow(['googlelogin','confirmLogin']);
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序
  • ¥15 onvif+openssl,vs2022编译openssl64
  • ¥15 iOS 自定义输入法-第三方输入法
  • ¥15 很想要一个很好的答案或提示
  • ¥15 扫描项目中发现AndroidOS.Agent、Android/SmsThief.LI!tr
  • ¥15 怀疑手机被监控,请问怎么解决和防止