こんにちは。昨年は一人ReactNativeカレンダーをやりましたが、今年は業務が忙しくて無理そうなので、このカレンダーに参加させていただきます:)
さて、FacebookやTwitterでログインするモジュールは沢山ありますが、そのtokenを利用してFeedを取得する方法となると極端に情報がなくなります。今回はReact NativeでTwitterのフィードを取得するため方法を解説したいと思います。というより、むしろOauth1.0aをどうやって通すかの説明がメインになると思います。
まず、 twitterのトークンを取得しましょう。これは、react-native-oauthなどを使えば比較的容易に取得できると思います。この手の多くがNativeにリンクするかたちで実現しているので、ドキュメントがしっかりしたものを選ぶといいでしょう。この点、react-native-ouath
はしっかりしたREADMEがあるので利用しやすいかと思います。ただiOSの場合は、PODを利用して、インストールするので将来的にPODで管理したくない人には不向きかもしれません。
一度、インストールしてしまえば、下記のようにcreadentials
を取得できます。 私はこのファイルと/app/utils/Auth.js
みたいに保存して利用してます。
const config = {
twitter: {
consumer_key: '*',
consumer_secret: '*',
},
facebook: {
client_id: '*',
client_secret: '*'
},
}
// Create the manager
const manager = new OAuthManager('myApp')
// configure the manager
manager.configure(config);
module.exports = {
authenticate(providerName) {
return new Promise((resolve, reject) => {
let promise;
switch (providerName) {
case 'twitter':
promise = manager.authorize('twitter');
break;
case 'facebook':
promise = manager.authorize('facebook', {scopes: 'user_posts'});
break;
default:
console.log('Unknown provider');
break;
}
if(promise){
promise.then((res) => {
resolve({ credentials: res.response.credentials, uuid: res.response.uuid });
}).catch((error) =>{
reject(error);
});
}else{
reject('unknown provider');
}
});
}
}
Twitterの場合、OAuth1.0aなので、Credential取得後にすることは、Oauthヘッダやそれに使われるSignatureの作成を行う必要があります(twitterのドキュメントに詳しく記載されています)。これは最近の言語ならライブラリやモジュールで実装されているのですが、ReactNativeの場合、Nodeのコアライブラリでハッシュ計算とかをしてるのでNodeのモジュールで使えません。色々試してみたところ、ohauthというのがPure JSで実装されており、一部の機能をTwitter用に書き換えれば使えることがわかりました。
結論からいうと、nonceの32文字の書き換えぐらいでしたが、ここまでに何度Oauth signature checkerを通したことでしょう^^;
Headerを作るコードは下記で、
var ohauth = require('ohauth');
...
generateTwitterOauthHeader(method, url, urlParams, token, tokenSecret){
let headerParams = {
oauth_consumer_key: config.twitter.consumer_key,
oauth_nonce: this._getNonce(),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: ohauth.timestamp(),
oauth_token: token,
oauth_version: "1.0"
};
headerParams = Object.assign(headerParams, urlParams);
console.log(headerParams);
let baseString = ohauth.baseString(method, url, headerParams)
console.log(baseString);
let sig = ohauth.signature(config.twitter.consumer_secret, tokenSecret, baseString) // function(oauth_secret, token_secret, baseString) {
console.log(sig)
headerParams["oauth_signature"] = sig;
let header = ohauth.authHeader(headerParams);
console.log(header);
return header
},
_getNonce(){
for (var o = ''; o.length < 32;) {
o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
}
return o;
}
これをfetch()
のheaderに差し込んで使います。
import Auth from './Auth';
const homeTimelineUrl = 'https://api.twitter.com/1.1/statuses/home_timeline.json';
module.exports = {
getHomeTimeLine(token, tokenSecret){
return new Promise((resolve, reject) => {
let oauthHeader = Auth.generateTwitterOauthHeader('GET', homeTimelineUrl, {count: 100}, token, tokenSecret);
fetch(`${homeTimelineUrl}?count=100`,
{
method: 'GET',
headers: {
'Authorization': 'OAuth '+oauthHeader,
}
}
)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
resolve(responseJson);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
}
できてしまえば簡単ですが、Oauth1.0は面倒臭いですね。昔同じようなことを書いたのを思い出しました。