CakePHP で OAuth 認証を使ったログイン認証・保持や会員データの保持・更新をするコード

CakePHP で OAuth 認証をしてログインなどをしたり、会員データをデータベースに持っておく仕組みを作る際のサンプルを紹介します。CakePHP 1.3 での動作確認をしています。今後出てくる CakePHP 2.x 系では動作確認しておりませんのでご了承ください。

OAuth 認証ライブラリを組み込み

以下のページより OAuth のライブラリを読み込みます。
OAuth consumers for CakePHP – by cakebaker

このファイルを vender/ に入れます。

OAuth 認証できる会員ログインするコントローラーとモデル

完成形を公開しておきます。いろいろと最低限動くようにするとこのような感じでしょうか。このコントローラーとモデルを使うとできることを下に箇条書きにしておきます。

  • Twitter のアカウントでログインをすることができる。
  • 初回のログインでは新規アカウント登録がされる、すでにアカウントがある場合はアカウントのログイン時間やトークン、ユーザー名などが最新の状態に更新される。
  • ログインの認証や保持は Auth コンポーネントを使っておりうまい具合に OAuth と連携している。

コントローラー

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?php
App::import('Vendor', 'oauth', array('file' => 'OAuth/oauth_consumer.php'));
class MemberController extends AppController
{
	public 
		$name = 'Member',
		$components = array('Auth');
 
	function beforeFilter()
	{
		$this->Auth->userModel = 'Member';
		$this->Auth->allow('index', 'login', 'twitter', 'twitter_callback');
		$this->Auth->fields = array('username' => 'access_token_key', 'password' => 'access_token_secret');
		$this->Auth->loginAction = '/member/';
 
		parent::beforeFilter();
	}
 
	public function index()
	{
		$auth = $this->Session->read('Auth');
		if(isset($auth['Member']['user_id'])) {
			$this->set('title_for_layout', $auth['Member']['user_name'] . 'さんのマイページ');
		} else {
			$this->set('title_for_layout', 'ゲストさんのマイページ');
			$this->render('guest_index');
		}
	}
 
	public function login()
	{
		$auth = $this->Session->read('Auth');
		if($auth['Member']['user_id']) {
			$this->redirect('/member/');
		} else {
			$this->redirect('/member/twitter');
		}
	}
 
	public function logout()
	{
		$auth = $this->Session->read('Auth');
		if($auth['Member']['user_id']) {
			$this->Auth->logout();
			$this->redirect('/member/');
		} else {
			$this->redirect('/member/');
		}
	}
 
	public function twitter()
	{
		$consumer = $this->createConsumer();
		$requestToken = $consumer->getRequestToken('https://twitter.com/oauth/request_token', 'http://hoge.com/member/twitter_callback');
		$this->Session->write('twitter_request_token', $requestToken);
		$this->redirect('https://twitter.com/oauth/authorize?oauth_token=' . $requestToken->key);
	}
 
	public function twitter_callback()
	{
		$consumer = $this->createConsumer();
		$requestToken = $this->Session->read('twitter_request_token');
		$accessToken = $consumer->getAccessToken('https://twitter.com/oauth/access_token', $requestToken);
		if($accessToken != '') {
 
			// Twitter からユーザーデータを取得
			$json = $consumer->get($accessToken->key, $accessToken->secret, 'http://twitter.com/account/verify_credentials.json', array());
			$twitterData = json_decode($json, true);
 
			$consumer->post($accessToken->key, $accessToken->secret, 'http://twitter.com/statuses/update.json', array('status' => '接続しました。'));
 
			$this->Member->update(
					Array(
						"user_id" => $twitterData['id_str'],
						"user_name" => $twitterData['screen_name'],
						"access_token_key" => $accessToken->key,
						"access_token_secret" => $accessToken->secret,
						)
					);
 
			$user['Member']["access_token_key"] = $accessToken->key;
			$user['Member']["access_token_secret"] = $accessToken->secret;
 
			if ($this->Auth->login($user)) {
				$this->Session->write('hoge_request_token', $this->getRequestToken());
				$this->redirect('/member/');
			}
			$this->render('index');
		} else {
			$this->cakeError('error404');
		}
	}
 
	private function getRequestToken()
	{
		$auth = $this->Session->read('Auth');
		$token = md5($auth['Member']['created'] . $auth['Member']['id'] . 'SixjDklLT5mRuDEgRZPGQxYxpy9kC7iI');
		return $token;
	}
 
	private function requestAuth()
	{
		$auth = $this->Session->read('Auth');
		$tokenAuth = $this->Session->read('hoge_request_token');
		$tokenTemp = $this->getRequestToken();
		if($tokenAuth == $tokenTemp) {
			return true;
		} else {
			return false;
		}
	}
}

モデル

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class Member extends AppModel
{
	var $name = 'Member';
	var $useTable = 'members';
 
	/*
	 * うまい具合にメンバーの登録・更新ができる関数
	 */
 
	public function update($member_data)
	{
		$member = $this->find('first', array('conditions' => array('user_id' => $member_data['user_id'])));
		if($member) {
			$member_data['id'] = $member['Member']['id'];
		}
		$this->create();
		$this->save(Array("Member" => $member_data));
	}
}

データベースの会員テーブル

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE IF NOT EXISTS `members` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(64) NOT NULL,
  `user_name` varchar(64) NOT NULL,
  `access_token_key` text NOT NULL,
  `access_token_secret` text NOT NULL,
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_id` (`user_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

本記事のコードは動作を理解した上でご利用ください。またバグやセキュリティホールなど御座いましたら管理者までご連絡ください。

コメント

  1. jayHatmakerさんのコメント

    コントローラ名ですが、複数形のMembersControllerになるんじゃないかな?
    あと、最後のテーブルの「updated」って「modified」じゃない?