Monaca Docs
検索…
Twitter アプリ
ここでは、Twitter 上でのOAuthを利用したシングルサインオン ( Single Sign-On/SSO ) の方法を解説します。 シングルサインオンには、InAppBrowser プラグインと、サードパーティ製 advanced-http プラグイン を使用し、また、OAuthに必要なシグネチャは oauth-signature ライブラリ を利用します。
認証成功後、ユーザーの基本情報をアプリ上に表示したり、ツイートを投稿することが出来ます。
サードパーティー製 Cordova プラグインを確認する場合は、カスタムビルドデバッガー ( Android 版 または iOS 版 ) を作成する必要があります。

デモ

テスト環境
  • Android 11.0
  • iOS 14.3

事前準備

Twitter の Consumer Key と Consumer Secret の確認方法

TwitterAPIを利用するためには、デベロッパーアカウントの登録が必要となります。 Twitter Developer Account よりデベロッパーアカウントを登録します。
次に、『 Twitter Developer Portal 』ページ上で、アプリを登録し、Consumer Key (API key ) と Consumer Secret (API secret key) 、Bearer token を発行します。
  1. 2.
    Standalone Apps を、画面下部の Create App ボタンより作成します。 (Standalone Apps を作成する代わりに、Projects配下にAppsを作成でも構いません)
  2. 3.
    Name ( アプリ名 )、Description ( アプリの説明 )、Website ( アプリのダウンロード元となる URL )を入力します。(※ アプリ名には、すでに利用されている名前は利用できません。また、1日あたりに作成出来るアプリ数には、上限があります。)
  3. 4.
    「Callback URL」(任意:認証成功後に表示されるページ。)を入力します。 今回のサンプルアプリでは、 mymonacaapp:// と設定します。適時、自分のアプリ用のものに変更してください。 なお、このCallback URLはアプリの実装時にも必要になります。
  4. 5.
    Settings タブを選択して、 App permissions から、 Read and Write 権限を許可します。アプリからツイートを行わない場合は、Read 権限のみ許可します。
  5. 6.
    Settings タブを選択して、 Authentication から、 3-legged OAuth を有効にします。

プラグインのインポート

シングルサインオンを実現させるため、InAppBrowser プラグインと サードパーティ製 advanced-http プラグイン を使用します。 また、OAuthに必要なシグネチャを作成するために oauth-signatureライブラリを使用します。
  1. 1.
    Monaca クラウド IDE から 設定 → Cordova プラグインの管理 を選択します。
  2. 2.
    InAppBrowser プラグインを 有効 にします。
3. ボタン「Cordovaプラグインのインポート」をクリックして、「URLもしくはパッケージ名を指定します」にチェックをし、パッケージ名に cordova-plugin-advanced-http を入力し、OKボタンをクリックします。

JSコンポーネントのインポート

  1. 1.
    Monaca クラウド IDE から 設定 → JS/CSSコンポーネントの追加と削除 を選択します。
  2. 2.
    コンポーネントの検索フォームに oauth-signature-js と入力して検索。検索結果から oauth-signature-js をインストールします。その後、読み込み対象の選択にて、 components/oauth-signature-js/dist/oauth-signature.js を選択し、保存します。 なお、oauth-signature.jsライブラリは、 BSD-3-Clause であるので、アプリのソースコード、バイナリコードの配布を行う場合はご注意下さい。

アプリの解説

ファイル構成

ファイル
説明
index.html
アプリ画面のページ
css/style.css
アプリのスタイルシート
js/app.js
アプリの実行時にさまざまな処理を行う JavaScript ファイル

HTML の解説

index.html

1
<!DOCTYPE HTML>
2
<html>
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6
<meta http-equiv="Content-Security-Policy" content="default-src * data: gap: content: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
7
<script src="components/loader.js"></script>
8
<link rel="stylesheet" href="components/loader.css">
9
<link rel="stylesheet" href="css/style.css">
10
<script src="js/app.js"></script>
11
12
</head>
13
<body>
14
<h2>Twitter Sample</h2>
15
<div>
16
<button onclick="connect()">Connect !</button>
17
<p>Your Id:
18
<span id="tw-id"></span>
19
</p>
20
<p>Your Name:
21
<span id="tw-name"></span>
22
</p>
23
<hr>
24
<button id="showMe" onclick="showMe()">Show Me</button>
25
<p>Your Info:
26
<span id="tw-profile"></span>
27
</p>
28
<img id="tw-profile-image" class="profile">
29
<hr>
30
<p>
31
<textarea id="tweetText" rows=5 cols=40>Hello</textarea>
32
</p>
33
<button id="tweetBtn" onclick="sendTweet()">Send Tweet</button>
34
</div>
35
</body>
36
</html>
Copied!
アプリ画面となるページです。
このページは、大きく3つのブロックに分かれています。それぞれのブロックは、 <hr> タグにより区切られています
  1. 1.
    ログイン ブロック:
    Twitterログイン画面に移行するボタンと、ログイン後にユーザーID、ユーザー名(スクリーン名)を表示するコンポーネントがあります。
  2. 2.
    プロフィール ブロック:
    ログインユーザーのプロフィールを取得するボタンと、取得成功後にそれを表示するコンポーネントがあります。
  3. 3.
    ツイート ブロック:
    テキストエリアと、ツイートするボタンがあります。

JavaScript の解説

app.js

1
const apiKey = '【Consumer Key(API key)】';
2
const secretKey = '【Consumer Secret (API key secret)】';
3
const callbackURL = '【登録したコールバックURL(スキーム)】';
4
5
const signatureMethod = "HMAC-SHA1";
6
const version = "1.0";
7
8
const requestTokenURL = "https://api.twitter.com/oauth/request_token";
9
const loginURL = "https://api.twitter.com/oauth/authorize"
10
const accessTokenURL = "https://api.twitter.com/oauth/access_token";
11
const updateURL = "https://api.twitter.com/1.1/statuses/update.json";
12
const usersShowURL = "https://api.twitter.com/1.1/users/show.json";
13
14
let model = {};
15
16
function percentEncode(str) {
17
return encodeURIComponent(str).replace(/[!'()*]/g, char => '%' + char.charCodeAt().toString(16));
18
}
19
20
function getNonce() {
21
const array = new Uint8Array(32);
22
window.crypto.getRandomValues(array);
23
return Array.from(array).map(uint => uint.toString(16).padStart(2, '0')).join('');
24
}
25
26
function oauthSend(url, method, accessTokenSecret, data, oauth_params, cb) {
27
const timestamp = (Math.floor(Date.now() / 1000)).toString(10);
28
const parameters = Object.assign(
29
{},
30
oauth_params,
31
{
32
oauth_nonce: getNonce(),
33
oauth_signature_method: signatureMethod,
34
oauth_timestamp: timestamp,
35
oauth_version: version
36
},
37
data
38
);
39
const signature = oauthSignature.generate(method.toUpperCase(),
40
url,
41
parameters,
42
secretKey,
43
accessTokenSecret
44
);
45
const authorizationHeader = "OAuth " + Object.keys(parameters).map((key) => {
46
return percentEncode(key) + '="' + percentEncode(parameters[key]) + '", '
47
}).join('') + 'oauth_signature=\"' + signature + '\"';
48
49
const urlWithParams = method.toUpperCase() === "GET" ?
50
url + "?" + Object.keys(data).map(function(k) {
51
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
52
}).join('&') : url;
53
54
cordova.plugin.http.sendRequest(urlWithParams, {
55
method: method,
56
headers: {'Authorization': authorizationHeader},
57
data: data,
58
serializer: null
59
}, (res) => {
60
cb(res);
61
}, (error) => {
62
alert(error.error);
63
});
64
}
65
66
function connect() {
67
oauthSend(requestTokenURL, 'post', "", {}, {
68
oauth_callback: callbackURL,
69
oauth_consumer_key: apiKey,
70
}, function (res) {
71
openLoginDialog(res.data);
72
});
73
}
74
75
function openLoginDialog(res) {
76
const oauth = res.split('&')[0];
77
const url = loginURL + "?" + oauth;
78
const ref = cordova.InAppBrowser.open(url, "_blank", 'location=yes,beforeload=get');
79
ref.addEventListener('beforeload', beforeLoad(ref));
80
}
81
82
function beforeLoad(ref) {
83
return function (event, cb) {
84
if (event.url && event.url.startsWith(callbackURL) ) {
85
const url = new URL(event.url);
86
const params = Array.from(url.searchParams.entries()).reduce(
87
function (acc, cur) {
88
acc[cur[0]] = cur[1];
89
return acc;
90
} , {}
91
);
92
ref.close();
93
getAccessToken(params);
94
} else {
95
cb(event.url);
96
}
97
};
98
}
99
100
function getAccessToken(params) {
101
oauthSend(accessTokenURL, 'post', "", {}, {
102
oauth_verifier: params.oauth_verifier,
103
oauth_token: params.oauth_token,
104
oauth_consumer_key: apiKey,
105
}, function (res) {
106
const params = Array.from(new URLSearchParams(res.data).entries()).reduce(
107
function (acc, cur) {
108
acc[cur[0]] = cur[1];
109
return acc;
110
} , {}
111
);
112
document.getElementById('tw-id').innerHTML = params.user_id;
113
document.getElementById('tw-name').innerHTML = params.screen_name;
114
model.oauth_token = params.oauth_token;
115
model.oauth_token_secret = params.oauth_token_secret;
116
model.user_id = params.user_id;
117
});
118
}
119
120
function sendTweet() {
121
const text = document.querySelector("#tweetText").value;
122
oauthSend(updateURL, 'post', model.oauth_token_secret, { "status": text }, {
123
oauth_token: model.oauth_token,
124
oauth_consumer_key: apiKey
125
}, function (res) {
126
alert("Tweet しました");
127
});
128
}
129
130
function showMe() {
131
oauthSend(usersShowURL, 'get', model.oauth_token_secret, { "user_id": model.user_id }, {
132
oauth_token: model.oauth_token,
133
oauth_consumer_key: apiKey
134
}, function (res) {
135
const profile = JSON.parse(res.data);
136
document.querySelector("#tw-profile").innerHTML =
137
"name: " + profile["name"] + "<br>" +
138
"screen_name: " + profile["screen_name"] + "<br>" +
139
"location: " + profile["location"] + "<br>" +
140
"description: " + profile["description"] + "<br>";
141
document.querySelector("#tw-profile-image").src = profile["profile_image_url_https"].replace("_normal", "");
142
});
143
}
Copied!
ファイルの最初3行で、事前準備で取得した APIキー(コンシューマキー)、APIキーシークレット(コンシューマシクレット)、コールバックURLを設定します。
1
const apiKey = '【API key(コンシューマキー)】';
2
const secretKey = '【API key secret(コンシューマシークレット)】';
3
const callbackURL = "【登録したコールバックURL(スキーム)】";
Copied!
Connectボタンをタップすると認証画面が表示されます。
ログイン成功後、アクセストークンとユーザーIDを変数 model に保持します。 今回のサンプルアプリでは、ログアウト機能はないため、ログイン状態を解除するには、アプリをタスクからkillすることが必要です。
次に Show Me ボタンをタップすると、ログインしたユーザー情報と、アイコンが表示されます。 さらに、Send Tweet ボタンをタップすると、テキストフォームに入力したメッセージが、Twitterへ投稿されます。
Twitterのログイン画面にて、パスワードを「保持します(Remember me)」にチェックした場合、次回からアカウントとパスワードは、入力せずにログイン済みの状態で認可画面になります。Twitterからログアウトしたい場合は、認可画面で右上のアイコンから、サインアウトして下さい。
このアプリでは、ログイン情報(アクセストークン)を 変数modelに一時的に保持しているため、アプリを再起動するとログイン情報は失われてしまいます。ログインしている状態を維持したい場合は、アクセストークンとユーザーIDをlocalstorage等の永続化可能な場所に保存します。
最終更新 21d ago