ブラウザにOneDriveAPIのJSONを渡して画像を表示

 OneDriveのAPIを使うとJSONで任意の情報を取得できる。前回に任意のディレクトリの子アイテム一覧をJSONで取得したので、今回はブラウザでそのJSONを受け取って、JSONに含まれているURLから画像ファイルを表示する…というJavaScript。

(function () {

document.getElementById("imageButton").addEventListener("click", function () {
var xhr = new XMLHttpRequest();
xhr.open("get", "/Master/OneDrive/Get");
xhr.responseType = "json";
xhr.addEventListener("load", function () {
var obj = JSON.parse(xhr.response);
var values = obj["value"];
for (var v in values) {
(function () {
var img = new Image();
img.src = values[v]["@@content.downloadUrl"];
img.width = 250;
document.getElementById("images").appendChild(img);
})();
}
});
xhr.send();
});
})();
comment: 0

OneDrive APIについて

前回

 前回にOneDriveでトークンの取得までをやったので、今回はそれを使ったディレクトリやファイルの取得までをちょっとつついておく。

 基本的な形は下記。
https://api.onedrive.com/{api-version}/drive/root/children?access_token={access token}

 ぼくは任意のディレクトリに入っているアイテム一覧がほしいので下記のようにカスタマイズ。https://api.onedrive.com/{api-version}/drive/items/{id}/children?access_token={access token}
https://dev.onedrive.com/resources/item.htm
 ディレクトリのIDは自分でブラウザを使ってOneDriveにログインして、IDを知りたいディレクトリに入ればURLのクエリにそれを確認することができる。

 あとはパラメータでオーダーやフィルターが使える。
https://api.onedrive.com/{api-version}/drive/items/{id}/children?access_token={access token}&orderby=name%20desc
https://dev.onedrive.com/odata/optional-query-parameters.htm
comment: 0

HTTPアクセスをするアプリのデバッグにFiddlerを使う

"Oh, my friend. How did you come to trade the fiddle for the drum?"
- Joni Mitchell


 アプリ、それがデスクトップでもWebアプリでもHTTPリクエストを含む場合、そのリクエストのデバッグがちょっとやっかいになることがある。レスポンスはどのコードとともに返ってきている?そもそも意図したとおりのリクエストを投げられているか?などなど。そのあたりの情報をどう表示する?コンソールに?アプリのウィンドウにデバッグ時にだけ?ブラウザに渡して表示させる?などなど。
 そういうケースではぼくはFiddlerを使っている。これは通信を監視してくれるもので、リクエストやレスポンスがどういうデータで来ているかを表示してくれる。
http://www.telerik.com/fiddler

 ぼくは昨晩にASP.NET Core MVCアプリからOneDriveのOAuthを通そうとしているときにFiddlerを使った。↓がそのキャプチャである。


 ウィンドウ左半分にどこへのリクエストでレスポンスコードはなんだったかという浅めの情報が表示され、右半分に具体的なリクエストデータやレスポンスデータをテキストやらバイナリやらで表示してくれるようになっている。これでPOSTデータは自分の意図通りになっているかということや、エラーがあった場合にサーバから送られてきた生のメッセージを見ることができる。

 というわけでHTTPが絡むようなアプリを作るならFiddlerは便利。
comment: 0

C#: ASP.NET Core MVCのアプリでOneDriveのOAuthを使う

 ASP.NET Core MVCアプリでOneDriveのAPIを使いたいので、OAuthでトークンを取ってくるという使い始めの部分までをまとめる。

 まずアプリをOneDriveのDevCenterに登録する。
https://apps.dev.microsoft.com/

 サインインするとその先の登録アプリ一覧画面の右上にアプリ追加がある。



 必要情報の入力と取得。ClienIDとClientSecret(PasswordとPrivateKeyがあるがPasswordのほう)、入力したリダイレクトURIをメモ。認証コード取得時にリダイレクトURIも渡さないといけないのだが、それが間違っているとコードが降りてこない。


 DevCenterへのアプリ登録ができたらあとはC#コード。OneDriveでアプリの仕様を許諾して認証コードを持って帰ってきたユーザの処理。
[Route("OAuth")]

public async Task<string> AuthUserAsync()
{
var client_id = xxx;
var redirect_uri = xxx;
var client_secret = xxx;
var code = Request.Query["code"];

var httpClient = new System.Net.Http.HttpClient();

// まず持って帰ってきた認証コードを使ってトークンを取得する
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "client_id", client_id },
// ↓スラッシュとか入ってるだろうけどエスケープせずに入れてOK
{ "redirect_uri", redirect_uri },
{ "client_secret", client_secret },
{ "code", code },
{ "grant_type", "authorization_code" },
});
var codeResponse = await httpClient.PostAsync("https://login.live.com/oauth20_token.srf", content);
var codeResponseBody = await codeResponse.Content.ReadAsStringAsync();
var jsonObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(codeResponseBody);
var token = jsonObj["access_token"];

// 取得したトークンを使ってOneDriveにユーザ情報を要求する
var uri = $"https://api.onedrive.com/v1.0/drive?access_token={token}";
var tokenResponse = await httpClient.GetAsync(uri);
var tokenResponseBody = await tokenResponse.Content.ReadAsStringAsync();

// ユーザを確認できる情報が得られたのでごにょごにょする
// Foo(tokenResponseBody);

// return tokenResponseBody;

}
comment: 0

PythonアプリにGithubのOAuthを使う

 Web上に置いている自分の読書メモがある。これの環境移植を最近行ったのだが、せっかくなので認証をGithubのOauthを使うようにしてみた。その流れ。

 まずGithubでアプリを登録する。個人設定を開く。


 メニューからOAuthアプリを選ぶ。


 新しくアプリの認証を通す。


 必要な情報の入力。


 一覧にもどってアプリの認証情報をメモ。必要なのはClientIDとClientSecret。


 ここまでで事前準備は終了で、あとのやることはアプリ側。
 OAuthでの認証の流れは…
1.自サイトのリンクからGithub(あるいはOAuthを持っているほかのサイト)へ行ってもらう(ワンクリック)
2.Githubで、自サイトがそこの認証情報を使わせてもらうことをユーザーに許諾してもらう(ワンクリック)
3.Githubであらかじめ設定しておいたリダイレクト先URIにユーザーが認証コードを持ってリダイレクトされてくる
4.自サイトサーバが認証コードを使ってGithubにトークンを要求
5.トークンが帰ってきたらそれを使って再度自サイトサーバがGithubへ、今度はユーザーの個人認証情報を要求
6.Githubから自サイトサーバが受け取った個人認証情報で認証処理を完了させる
という流れ。
 自サーバが持つべきなのはGithubの指定の認証ページへのリンクと、そこからリダイレクトで帰ってきたときの処理をするハンドラの二つか。
 というわけでリダイレクトでGithubから帰ってきたユーザーの認証処理を行うハンドラの流れを書いておく。

 まず認証コードを使ってトークン取得。
        code = self.get_argument("code", None)

client_id = GITHUB_CLIENT
if code:
url = "https://github.com/login/oauth/access_token"
secret = GITHUB_SECRET
data = {
"code": code,
"client_id": client_id,
"client_secret": secret
}
p_data = urllib.parse.urlencode(data).encode(encoding='ascii')
with urllib.request.urlopen(url, data=p_data) as f:
res = f.read().decode("ascii")
token = res.replace("access_token=", "").replace("&scope=&token_type=bearer", "")


 レスポンスからトークンを抜粋する方法がアレなのは置いておく。次はトークンを使って個人情報をGithubからもらう。
            url = "https://api.github.com/user?access_token=" + token

with urllib.request.urlopen(url) as f:
res = f.read().decode("ascii")

info = json.loads(res)


 JSONで返ってくるので、そこからloginIDなどを参照する。OAuthのためのGithubサーバとのやり取りはこれでひと段落。あとはその情報で認証を与えられるなら処理を続行など。
 以下に認証コードを持って帰ってきたユーザーに認証を与える処理の一連を。
class OauthHandler(tornado.web.RequestHandler):

def get(self):
code = self.get_argument("code", None)
client_id = GITHUB_CLIENT
if code:
url = "https://github.com/login/oauth/access_token"
secret = GITHUB_SECRET
data = {
"code": code,
"client_id": client_id,
"client_secret": secret
}
p_data = urllib.parse.urlencode(data).encode(encoding='ascii')
with urllib.request.urlopen(url, data=p_data) as f:
res = f.read().decode("ascii")
token = res.replace("access_token=", "").replace("&scope=&token_type=bearer", "")

url = "https://api.github.com/user?access_token=" + token
with urllib.request.urlopen(url) as f:
res = f.read().decode("ascii")

info = json.loads(res)
user_id = info["login"]

db = self.settings["db"]
doc = db.user.find_one({"_id":user_id})

if doc is not None:
auth_token = self.generate_token()
dt = datetime.datetime.utcnow()
db.session.insert({"_id":auth_token, "createdAt":dt})
self.set_cookie("markofcain", auth_token, secure=True)
self.redirect("/")
else:
self.write("failed")

else:
url = "https://github.com/login/oauth/authorize?client_id=" + client_id
self.write("<a href='{0}'>Oauth auth</a>".format(url))

def generate_token(self):
""" Generate a 32-char alnum string. 190 bits of entropy. """
alnum = ''.join(c for c in map(chr, range(256)) if c.isalnum())
return ''.join(random.choice(alnum) for _ in range(32))
comment: 0