ここでは、Twitter 上でのOAuthを利用したシングルサインオン ( Single Sign-On/SSO ) の方法を解説します。 シングルサインオンには、InAppBrowser プラグインと、サードパーティ製 advanced-http プラグイン を使用し、また、OAuthに必要なシグネチャは oauth-signature ライブラリ を利用します。
3. ボタン「Cordovaプラグインのインポート」をクリックして、「URLもしくはパッケージ名を指定します」にチェックをし、パッケージ名に cordova-plugin-advanced-http
を入力し、OKボタンをクリックします。
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<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'">
<script src="components/loader.js"></script>
<link rel="stylesheet" href="components/loader.css">
<link rel="stylesheet" href="css/style.css">
<script src="js/app.js"></script>
</head>
<body>
<h2>Twitter Sample</h2>
<div>
<button onclick="connect()">Connect !</button>
<p>Your Id:
<span id="tw-id"></span>
</p>
<p>Your Name:
<span id="tw-name"></span>
</p>
<hr>
<button id="showMe" onclick="showMe()">Show Me</button>
<p>Your Info:
<span id="tw-profile"></span>
</p>
<img id="tw-profile-image" class="profile">
<hr>
<p>
<textarea id="tweetText" rows=5 cols=40>Hello</textarea>
</p>
<button id="tweetBtn" onclick="sendTweet()">Send Tweet</button>
</div>
</body>
</html>
const apiKey = '【Consumer Key(API key)】';
const secretKey = '【Consumer Secret (API key secret)】';
const callbackURL = '【登録したコールバックURL(スキーム)】';
const signatureMethod = "HMAC-SHA1";
const version = "1.0";
const requestTokenURL = "https://api.twitter.com/oauth/request_token";
const loginURL = "https://api.twitter.com/oauth/authorize"
const accessTokenURL = "https://api.twitter.com/oauth/access_token";
const updateURL = "https://api.twitter.com/1.1/statuses/update.json";
const usersShowURL = "https://api.twitter.com/1.1/users/show.json";
let model = {};
function percentEncode(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, char => '%' + char.charCodeAt().toString(16));
}
function getNonce() {
const array = new Uint8Array(32);
window.crypto.getRandomValues(array);
return Array.from(array).map(uint => uint.toString(16).padStart(2, '0')).join('');
}
function oauthSend(url, method, accessTokenSecret, data, oauth_params, cb) {
const timestamp = (Math.floor(Date.now() / 1000)).toString(10);
const parameters = Object.assign(
{},
oauth_params,
{
oauth_nonce: getNonce(),
oauth_signature_method: signatureMethod,
oauth_timestamp: timestamp,
oauth_version: version
},
data
);
const signature = oauthSignature.generate(method.toUpperCase(),
url,
parameters,
secretKey,
accessTokenSecret
);
const authorizationHeader = "OAuth " + Object.keys(parameters).map((key) => {
return percentEncode(key) + '="' + percentEncode(parameters[key]) + '", '
}).join('') + 'oauth_signature=\"' + signature + '\"';
const urlWithParams = method.toUpperCase() === "GET" ?
url + "?" + Object.keys(data).map(function(k) {
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
}).join('&') : url;
cordova.plugin.http.sendRequest(urlWithParams, {
method: method,
headers: {'Authorization': authorizationHeader},
data: data,
serializer: null
}, (res) => {
cb(res);
}, (error) => {
alert(error.error);
});
}
function connect() {
oauthSend(requestTokenURL, 'post', "", {}, {
oauth_callback: callbackURL,
oauth_consumer_key: apiKey,
}, function (res) {
openLoginDialog(res.data);
});
}
function openLoginDialog(res) {
const oauth = res.split('&')[0];
const url = loginURL + "?" + oauth;
const ref = cordova.InAppBrowser.open(url, "_blank", 'location=yes,beforeload=get');
ref.addEventListener('beforeload', beforeLoad(ref));
}
function beforeLoad(ref) {
return function (event, cb) {
if (event.url && event.url.startsWith(callbackURL) ) {
const url = new URL(event.url);
const params = Array.from(url.searchParams.entries()).reduce(
function (acc, cur) {
acc[cur[0]] = cur[1];
return acc;
} , {}
);
ref.close();
getAccessToken(params);
} else {
cb(event.url);
}
};
}
function getAccessToken(params) {
oauthSend(accessTokenURL, 'post', "", {}, {
oauth_verifier: params.oauth_verifier,
oauth_token: params.oauth_token,
oauth_consumer_key: apiKey,
}, function (res) {
const params = Array.from(new URLSearchParams(res.data).entries()).reduce(
function (acc, cur) {
acc[cur[0]] = cur[1];
return acc;
} , {}
);
document.getElementById('tw-id').innerHTML = params.user_id;
document.getElementById('tw-name').innerHTML = params.screen_name;
model.oauth_token = params.oauth_token;
model.oauth_token_secret = params.oauth_token_secret;
model.user_id = params.user_id;
});
}
function sendTweet() {
const text = document.querySelector("#tweetText").value;
oauthSend(updateURL, 'post', model.oauth_token_secret, { "status": text }, {
oauth_token: model.oauth_token,
oauth_consumer_key: apiKey
}, function (res) {
alert("Tweet しました");
});
}
function showMe() {
oauthSend(usersShowURL, 'get', model.oauth_token_secret, { "user_id": model.user_id }, {
oauth_token: model.oauth_token,
oauth_consumer_key: apiKey
}, function (res) {
const profile = JSON.parse(res.data);
document.querySelector("#tw-profile").innerHTML =
"name: " + profile["name"] + "<br>" +
"screen_name: " + profile["screen_name"] + "<br>" +
"location: " + profile["location"] + "<br>" +
"description: " + profile["description"] + "<br>";
document.querySelector("#tw-profile-image").src = profile["profile_image_url_https"].replace("_normal", "");
});
}
const apiKey = '【API key(コンシューマキー)】';
const secretKey = '【API key secret(コンシューマシークレット)】';
const callbackURL = "【登録したコールバックURL(スキーム)】";