この記事は 高知工科大 Advent Calendar 2015 の 12/13 の記事です
みなさん、こんちは〜。 12/13の記事を担当するmisaki7247です。
クリスマスまでの日が近づいてきてリア充どもがうきうきしだす時期になりましたが、みなさんいかがお過ごしですか?
記事に何を書くか色々と悩んだんですが、今日やったWindowsLiveの認証についてのことを書いてみようかなーと思います。
だってOneDriveをAndroidから使いたいのにさー...
Androidで利用する場合、日本語の情報がほぼねーんだもん!
DropboxとかGoogleDriveは割りと日本語の情報があるのにOneDriveがないのはおかしい!
で、WindowsLiveに認証さえすればOneDriveが操作できる!
ってことで書いていきまーす。
あ、OneDrive知らないとか言うそんなあなた。→Google
WindowsLiveへの認証の方式にはOAuth2.0が使われてます。 で、この認証方式ではアクセストークンを拾ってくれば認証成功で、私たちの勝ちとなります。
その後はファイルを煮るなり焼くなりすきにできる...ってことで、アクセストークンをぶんどりにいきましょー!
アクセストークンを取得する前に、まずここからアプリケーションの登録をする必要があります。登録方法は簡単なので割愛。
で、登録すればこんな画面が出てきます。
この中でクライアントID、クライアントシークレットが必要になるのでメモっときましょ〜。
はい、タイトルの通りですね。 アクセストークンを取得するにはまずCodeという文字列を取得する必要があります。
Codeを取得するには以下のようなURLにアクセスします。
https://login.live.com/oauth20_authorize.srf?
client_id=0000000123ABCD&scope=wl.signin%20wl.basic%20wl.offline_access%20wl.skydrive_update
&response_type=code&redirect_uri=https://login.live.com/oauth20_desktop.srf
この中で必ず変えないといけないのはclient_idの数値です。
scopeに関してはこのページを参考にして必要な物だけを入れましょー。
で、プログラムどうすんの?っていうとこーするの。(プログラム適当なのは急いでやってたから許してT_T )
public class Onedrivetest extends FragmentActivity {
public static String code = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.onedrive_test);
Button button = (Button)findViewById(R.id.login);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openWebView((WebView) findViewById(R.id.wv));
}
});
}
public String getCode(String url) {
String code = null;
String codeKey = "code=";
int idx = url.indexOf(codeKey);
if (idx != -1) { // 認証成功ページだった
code = url.substring(idx + codeKey.length()); // 「code」を切り出し
}
return code;
}
public void openWebView(WebView wv) {
wv.getSettings().setJavaScriptEnabled(true);
wv.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) { // ページ読み込み完了時
ViewSwitcher vs = (ViewSwitcher)findViewById(R.id.vs);
// ページurlからコードを取得
String pageUrl = view.getUrl();
code = getCode(pageUrl);
if (code == null) {
Log.v("onPageFinished", "コード取得成功ページ以外 url=" + url);
if (!(vs.getCurrentView() instanceof WebView)) { // WebViewが表示されてなかったら
vs.showNext(); // Web認証画面表示
}
} // コード取得成功
else {
vs.showPrevious(); // 元の画面に戻る
Log.v("onPageFinished", "コード取得成功 code=" + code);
}
}
});
String url = "https://login.live.com/oauth20_authorize.srf?client_id=0000000123ABCDD&scope=wl.signin%20wl.basic%20wl.offline_access%20wl.skydrive_update&response_type=code&redirect_uri=https://login.live.com/oauth20_desktop.srf";
wv.loadUrl(url);
}
}
で、レイアウトファイルはこちら。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.promise.t2p.onedrivetest">
<ViewSwitcher
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/vs">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="login"
android:id="@+id/login">
</Button>
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/wv">
</WebView>
</ViewSwitcher>
</RelativeLayout>
動かしてみるとこんな画面が表示されます。(Manifestでインターネット接続を許可しといてねー。)
サインインするとこんな画面に移ります。
ここで許可するとCodeがページのURLに表示されます。
こんな感じ。
https://login.live.com/oauth20_desktop.srf?
code=123abc456-12ab-1234-1234-1234abcd1234&lc=1043
これを取り出してやれば良いってことで、やり方はソースコード見てねー。
さてみなさん、Codeは取り出せましたね?
ってことで、本題のアクセストークンをぶんどってきましょうー!
で、アクセストークンですが、こんなURLにGETメソッドぶつけます。
https://login.live.com/oauth20_token.srf?client_id=0000000123ABCD
&client_secret=abcdefghzyxwvutsr12345&code=123abc456-12ab-1234-1234-1234abcd1234
&grant_type=authorization_code&redirect_uri=https://login.live.com/oauth20_desktop.srf
すると、こんなJSONが返ってきます。
{
"token_type": "bearer",
"expires_in": 3600,
"scope": "wl.signin wl.basic wl.offline_access wl.skydrive_update",
"access_token": "a_very_long_access_token_of_hundreds_of_characters",
"refresh_token": "a_very_long_refresh_token_of_hunderds_of_characters",
"user_id": "1234567890abcdefghij"
}
ってことで、このJSONを受け取ればあなたは勝ちです...!
ものは試し、やってみよー! ってことで、サンプルコードです。
自分はJSONのデータ持ってくるときにJackson(v2.6.4)、Spring for Android(v1.0.1)使ってるので、このコードはそれを使う場合のみ使用できます。
public class AuthenticationInfo {
public String token_type;
public int expires_in; // 有効時間
public String scope;
public String access_token;
public String refresh_token;
public String user_id;
public String toString() {
return "tokenType=" + token_type + "\naccessToken = " + access_token + "\nrefreshToken=" + refresh_token + "\nuserId=" + user_id;
}
}
public class Onedrivetest extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//省略
Bundle bundle = new Bundle();
bundle.putString("format", "json");
getSupportLoaderManager().initLoader(0, bundle, callbacks);
}
private LoaderCallbacks<String> callbacks = new LoaderCallbacks<String>() {
@Override
public void onLoadFinished(Loader<String> loader, String data) {
getSupportLoaderManager().destroyLoader(loader.getId());
}
@Override
public void onLoaderReset(Loader<String> loader) {
}
@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
CustomLoader loader = new CustomLoader(getApplicationContext(), args);
loader.forceLoad();
return loader;
}
};
public static class CustomLoader extends AsyncTaskLoader<String> {
private String mFormat;
public CustomLoader(Context context, Bundle bundle) {
super(context);
mFormat = bundle.getString("format");
}
@Override
public String loadInBackground() {
return getJson();
}
private String getJson() {
RestTemplate template = new RestTemplate();
template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String url =
"https://login.live.com/oauth20_token.srf?client_id=" + client_id + "&client_secret=" + client_secret + "&code=" + code + "&lc=1041&grant_type=authorization_code&redirect_uri=https://login.live.com/oauth20_desktop.srf";
try {
ResponseEntity<AuthenticationInfo> responseEntity = template.exchange(url, HttpMethod.GET, null, AuthenticationInfo.class);
AuthenticationInfo res = responseEntity.getBody();
Log.v("でーきたー", res.toString());
return res.toString();
} catch (Exception e) {
Log.d("Error", e.toString());
return null;
}
}
}
}
あら不思議、これでアクセストークンが取得できちゃうんですね〜。
ちなみに、取得したアクセストークンは800文字を超えてました。
簡単に認証できるし、みんなやってみよう! サンプルコードはここに上げておいたので気になる人はご自由にどぞー。
ってことで、私が担当の記事は以上となります!
明日の担当はFumiya Kawamuraさんです。 よろしくお願いします!