9.1 サーバ組んだ(まだ公開サーバじゃない)
Why
すぺっく
今までPCを組んだことはない。用途を考えるとクソザコでも良いんじゃね~、ッて思ってたが、なんか不安なので非常に中途半端なスペックになってる気がする。
種類 | 商品名 | 購入場所 | 値段 |
---|---|---|---|
マザーボード | GA-H81M-DS2V | ヨドバシカメラ京都 | 5370 |
CPU | Pentium G3220 | ヨドバシカメラ京都 | 7170 |
メモリ | UMAX Castor LoDDR3-4GB-1333 | ヨドバシカメラ京都 | 4880 |
HDD | TOSHIBA DT01ACA100 (1TB) | ドスパラ | 5910 |
ケース | ENERMAX Fulmo Q ECA3360B-BT(U3) | ドスパラ | 3480 |
電源 | Thermaltake PS-TR2-0450NPCBJP-B | ドスパラ | 6253 |
光学ドライブ | ASUS DRW-24D3ST | ドスパラ | 2270 |
DVI-HDMI変換ケーブル | 変換名人 DVHD-18GS | ドスパラ | 699 |
合計、36032円也。微妙に高いと思う。
なお、OSはUbuntu14.04をUSBメモリからインストールした。サーバ用途でUbuntuって不思議な気もするけど、使い慣れてるのが一番かなぁと思った。
マザーボード付属のCD、インストール必須かと思ったらそうじゃなかったみたい。光学ドライブは要らなかった。
組んでみた感想
手先が不器用な自分だが、思ったより簡単だった。プラスドライバーが一本あれば十分。
一番苦労したのは、ケースのフロントパネルを開けるところ。説明書にもなんかよく分からないイラストしか載ってなくて、いろいろやってるうちにどうにか開けることが出来た*1。
ケースに付いてたクーラーのピン数と、マザーボードのSYS_FAN
のピン数が合わなかったので、挿すのは止めておいた。挿したら常に全力でクーラーが回ることになるので、五月蝿くなると考えた。もちろん、CPUクーラーは回している。時々様子を見て、熱がヤバそうならクーラーを回すことにする。
お名前
このマシンの名前はsyaro
に決めた。
理由: 見た目の割に(?)中身が貧乏なのと、そこそこ頭(CPU)が良いから。
syaroです。
コンちゃんの復活
ruby
とかsqlite
とかtwitter gem
とかmecab
とか、まぁ色々入れて復旧した。環境構築は30分位で終わった。apt-get
様は偉大。Macの環境構築はクッソ面倒だった記憶がある。
apacheをインストール
サーバを立てたいので、apache
をインストールした。It works!まで行った。
redmineをインストール
タスク管理に便利だと噂のredmine
をインストールした。
インストールは結構骨の折れる作業だと聞いていたが、このページを参考にすれば20分くらいで終わった。
ついでにMySQLがインストールされた。
ぐえ
ぐえぐえ
*1:なんで開いたのか最後まで分からなかった
8.3 Web API: The Good Parts 5章~6章(完)
第5章 設計変更をしやすい Web API を作る
APIはなるべく更新しない
- APIが変わるとそれに依存するコードは期待通りの動作をしなくなる可能性が高い
- LSUDs向けAPIでは告知が大変
- SSKDs向けAPIではモバイルクライアントのバージョン問題
- 自分たちの使っているアプリではユーザのキャッシュ問題
バージョン管理
- パラメータでバージョン番号を取得する方法は微妙
- 省略された場合の動作は「最新のバージョンで対応する」というようにはいかない
- ユーザがバージョンについて意識していない可能性がある
- 省略された場合の動作は「最新のバージョンで対応する」というようにはいかない
- URIのパスの中にバージョンを埋め込むのが良い
- できるだけバージョンアップは避ける
- たとえば数値を返していたパラメータ
gender
を文字列を返すようにしたい場合、genderStr
を新たに設けて、後方互換性を保つ(バージョン番号の変化しない)変更のほうが良い
- たとえば数値を返していたパラメータ
バージョン番号の付け方
- 1.0.0のようにメジャー・マイナー・パッチの3つの数字で表すのが良い。
- よって、APIのURIに含めるバージョン番号はメジャーバージョン番号のみにするのが良い
- また、バージョン番号を示すことを明示するため「v1」のような形式にするのが良い
提供終了
- APIの公開が終了した時は、ステータスコード410(Gone)を返す仕様にしておく
- 利用規約にサポート期限を明記する
- 1年くらいが目安?最低6ヶ月
- 下手に長い年数を記述すると、多くのAPIをメンテナンスする必要が出てくるかもしれない
第6章 堅牢な Web API を作る
サーバ・クライアント間での情報の不正取得対策
- HTTPSにより通信を暗号化する
XSS・XSRF対策
Content-Type
をきちんとapplication/json
とする- IEのContent Sniffering対策には
X-Content-Type-Options
をnosniff
とする - 通常のブラウザでは送信されないリクエストヘッダの有無を確認する
X-Requested-With
がXMLHttpRequest
であるか
- データを16進数エスケープしておく
- セッションごとにユニークなトークンを作り照合する(XSRF対策)
- 直接APIを叩かれることを防ぐ
悪意あるユーザからのアクセス対策
- パラメータ改竄の可能性を考え、サーバサイドでバリデーションを行う
- 消費アイテムの個数に対してマイナスのパラメータを受け取った時、などに注意
- リクエスト再送信対策
- リクエスト送信時、ユニークな値を添える(Appleではreceiptと呼ばれる)
- 同じreceiptで送られてきたリクエストは弾く
セキュリティ関係のHTTPヘッダ
X-Content-Type-Options
X-XSS-Protection
X-Frame-Options
- 指定したページがフレーム内で読み込まれることを許可するか
deny
Content-Security-Policy
- そのページのIMG・SCRIPT要素などの読み込み先としてどこを許可するか
default-src 'none'
Strict-Transport-Security
Set-Cookie
session=hoge; Path=/; Secure; HttpOnly
Secure
属性は、そのクッキーはHTTPSでのみサーバに送信されるHttpOnly
属性は、そのクッキーはHTTP通信のみで使用され、JavaScript等からアクセス出来ない
大量アクセス対策
- ユーザごとにAPIに対するレートリミット(アクセス回数制限)を設ける
- 使用頻度の高いAPIは制限を緩くする
- リミットリセットのタイミングは、長くとも1時間くらい
- プログラムミス等でのうっかり大量アクセス時に、アクセス制限にかかる時間が長いとつらい
- 制限値を超えた場合はステータスコード429(Too Many Requests)を返す
- レートリミットを知るためのAPIを用意する
付録A Web API を公開する際にできること
- APIドキュメントを提供する
- ドキュメント制作用のサービスやツールもある
- サンドボックスAPIを提供する
- テスト環境
- API仕様は本番環境と同じものにする
- api.sandbox.example.comのようにホスト名を変える
まとめ
- APIバージョンは
v1
の形式でURI中に含める - APIはなるべく後方互換性のあるバージョンアップに留める
- 提供終了時の仕様やサポート期限を明記する
- HTTPSで
Content-Type
をきちんとapplication/json
とする- セキュリティヘッダはとりあえずぶち込んでおく
- レートリミットを設ける
- レートリミット情報をきちんとユーザに渡す配慮も忘れずに
- APIドキュメントをちゃんと書く
- サンドボックスAPIも提供するとベター
感想
- 付録BのWebAPIチェックリストが便利
8.2 Web API: The Good Parts 3章~4章
第3章 レスポンスデータの設計
JSONP
JSONをブラウザに渡す際、JavaScriptで以下のようにpaddingしたものをJSONPという。
callback({"id":123, "name":"Jack"})
JSONPが考えだされた背景には、同一生成元ポリシーによりXHTTPRequestは同じ生成元へのアクセスしか行うことが出来ないがscript要素はその制限の対象外であるということがある。つまり、抜け道としての手段である。そのため、必要な場合のみサポートするという姿勢を取ったほうが良い。
JSONPをサポートする際は、クエリパラメータとしてコールバック関数の名前を指定させるほうが良い。
以下に理由を説明する。まず、グローバル変数にJSONを渡す仕様は、グローバルを汚染してしまう。次に、コールバック関数名を固定する方法は、関数名の衝突が考えられ、柔軟性がない。よって、コールバック関数の名前をユーザーが指定できるような設計にすべきである。この時のパラメータ名にはcallback
が多用される。
データの内部構造
ユーザーが必要とするであろう情報を返す
たとえば、SNSの友達一覧を取得するAPIでユーザーIDの配列だけが返されても、ユーザーはそのIDを利用して別のAPIを呼ぶ必要があり、不便な上にオーバーヘッドが増加する。よって、IDの他に名前等の情報も返すべきである。
レスポンス内容をユーザーが選べるようにする
上記方針でレスポンス内容を設計すると、ユーザーに返すデータが膨大になる。そこで、いくつかのデータセットを選択肢として与えて、どのデータセットを渡すかユーザーに選択させる設計を行ったほうが良い。この時のパラメータ名にはfields
が多用される。
エンベロープは不必要
すべてのAPIを同じ構造でくるむことをエンベロープという。たとえば、すべてのAPIを以下のような構造にくるむと、一見良い設計に思える。
{ "header": { "status": "success", "errorCode": 0 }, "response": { ... } }
しかし、APIはそもそもHTTPを介しているので、HTTPというエンベロープが存在する。そのため、実際に利用される以外のメタデータに関しては、HTTPを利用する方が理に適っている。
データはなるべくフラットに
深い階層にデータを置くべきではない。これは、JSONのデータサイズを大きくしないようにするためである。しかし、階層化したほうが絶対に良い場合はそうしたほうが良い。
配列はオブジェクトとして包む
配列で包める場合も、オブジェクトで包むほうが良い。以下の様なメリットが有る。 * レスポンスデータが何を示しているものか分かりやすい * レスポンスデータをオブジェクトに統一できる * セキュリティリスクを回避できる セキュリティリスクについて、全体を配列で包むとそのJSONはJavaScriptとして正しいものになり、レスポンスに不正コードを仕込まれる可能性がある。オブジェクトの場合はそれ単体ではJavaScriptとして正しいコードではないため、ブラウザからアクセスしても不正コードは実行されない。
日付のフォーマット
HTTPヘッダで用いられているRFC3339を利用するのが良い。2015-10-12T11:30:22+09:00
のような形式である。
大きな数字
大きな数字は、数値データではなく文字列として返した方が良い。ユーザーのプログラムでのオーバーフローを防ぐためである。
エラーの伝え方
エラーが発生した場合は、おおよその意味をHTTPのステータスコードで返し、HTTPヘッダまたはJSON内にエラーの詳細を記述すれば良い。 また、エラー発生の際にHTMLが返ってしまうことは避け、メンテナンス時にもきちんとJSONを返す(ステータスコードは503)。
第4章 HTTPの仕様を最大限利用する
なぜHTTPの仕様を利用するのか?
前章で述べたように、メタデータをユーザーに渡すためのエンベロープとして使えるため。
ステータスコードの利用
大まかに、200番台:成功、300番台:追加で処理が必要、400番台:クライアントのリクエストに起因するエラー、500番台:サーバエラーである。 以下、APIに必要そうなやつだけ。
200:OK
PUT
PATCH
メソッドで正常にデータ更新が出来た時。
201:Created
POST
メソッドで、正常にデータが新規登録された時。
202:Accepted
処理は受理されたが、まだ完了していない時に返すステータスコード。
204:No Content
レスポンスが空の時に利用。DELETE
メソッドでデータの削除を行った時。
401:Unauthorized
「認証がなされていない(アクセスユーザーが特定できない)」。アクセスにユーザー情報が必要なAPIで、トークン無しでアクセスしてきた場合。
403:Authorization
「アクセス権限がない(ユーザーは特定できたが、そのユーザーに操作権限がない)」。許可されたユーザー以外のトークンでアクセスしてきた場合。
404:Not Found
存在しないユーザー情報にアクセスしようとした場合など。ただし、エンドポイントそのものが存在しないのか、データが存在しないのかが判別できないため、詳しい情報を付加するのが親切。
405:Method Not Allowed
エンドポイントは存在しているが、そのアクセスメソッドは許可されていない。
406:Not Acceptable
クライアントが指定してきたデータ形式にAPIが対応していない(たとえば、JSONしか対応していないのにXMLを指定してきた時)。
409:Conflict
リソースの競合。たとえば、ユニークキーを指定して新規登録するようなAPIで、重複キーを送ってきた場合。
410:Gone
かつて存在したが今は存在しないデータにアクセスしてきた場合。ただし、410を実装するなら、過去のデータを全て残しておく必要があり、セキュリティ上問題がある可能性もある(かつて登録されたメールアドレスなどが分かってしまう可能性がある)。
429:Too Many Requests
アクセス回数が許容範囲の限界を超えた。
503:Service Unavailable
サーバが一時的に利用できない。メンテナンス時など。
キャッシュについて
期限切れモデル
Cache-Control
レスポンスヘッダまたはExpires
レスポンスヘッダを利用して、データの有効期限を指定する。プロキシサーバで蓄えられたデータが再利用されるため、処理が高速になる。
検証モデル
Last-Modified
レスポンスヘッダとETag
(エンティティタグ)レスポンスヘッダを利用して、オリジンサーバとプロキシサーバの持つデータが一致しているか確認する。ETag
には、レスポンスデータのハッシュ値などが入る。この方式では、期限切れモデルと違いオリジンサーバとの通信が発生するため、レスポンスデータが膨大な場合には効果があるが、それ以外の場合はあまり意味を成さない。
キャッシュさせたくない場合
Cache-Control
ヘッダにno-cache
を入れる。
メディアタイプの指定
JSONの場合、Content-Type
ヘッダにapplication/json
を入れる。指定しなかった場合、XSSの影響を受ける可能性がある。
{"data":"<script>alert('xss');</script>"}
クロスオリジンリソース共有
同一生成元ポリシーによりXHTTPRequest
で異なるドメインに対してアクセスは出来ない。しかし、CORSを行うことによって特定のアクセス元からのアクセスを許可することが可能である。
リクエストのOrigin
ヘッダにアクセス元を指定する。
レスポンスのAccess-Control-Allow-Origin
ヘッダに、CORSを許可するアクセス元を指定する。ワイルドカードの利用が可能。
CORSとユーザー認証情報
リクエストでCookie
やAuthentication
ヘッダにユーザー認証情報がセットされている場合、サーバはレスポンスでAccess-Control-Allow-Credentials
ヘッダにtrue
をセットする必要がある。
独自のHTTPヘッダを定義する場合
X-AppName-
を接頭辞として付けることが一般的であったが、AppName-
で十分であるという議論がなされている。
まとめと感想
8.1 Web API: The Good Parts 1章~2章
- 作者: 水野貴明
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/11/21
- メディア: 大型本
- この商品を含むブログ (3件) を見る
APIの設計についての200ページ位の本。サクッと1月中旬までに読みたい(できるかな)。
読んでて気になったとことか雑多に纏めていこうかなーと思う。
第1章 Web APIとは何か
Web APIの定義
URIにアクセスすることで、情報を(主に)JSONで取得できるようなもの。つまり、サーバとクライアントとの橋渡しとなる部分で、ブラウザを通して人間が読むためのものではなく、第三者がプログラムを通して利用することを前提としている。
第2章 エンドポイントの設計とリクエストの形式
URI設計
覚えやすく、どんな機能を持つURIなのかひと目で分かるものが良い。
具体的には、以下の通り。
短く入力しやすい
http://api.example.com/service/api/search より http://api.example.com/search が良い。
人間が読んで理解できる
http://api.example.com/s より http://api.example.com/search が良い。
大文字小文字が混在していない
getUserNameとか。こういう名前を付けなければならない状況が発生するのは設計ミス。
改造しやすい(Hackableである)
http://api.example.com/items/123456 というURIは、ID:123456のアイテムに関するURIで、番号を変えれば他のアイテム情報にもアクセスできることが容易に想像可能。
サーバ側のアーキテクチャが反映されていない
APIの形式をデータベースのテーブル構成等に合わせる必要はない。また、どんな言語を利用しているかをURIに反映させる必要もない。逆に、そのような情報を間接的に公開してしまうことで、攻撃者にとって有益な情報を与えてしまうことになる。
ルールが統一されている
http://api.example.com/items/123456 と http://api.example.com/friends?id=123456 のようなURIを混在させない
HTTPメソッドの利用
HTTPメソッドにはGET・POSTの他にも、PUT・DELETE等も存在する。エンドポイントは一箇所にして、メソッドによって操作を変更するのがHTTPの理念に沿っている。
メソッド名 | 説明 |
GET | リソースの取得 |
POST | リソースの新規登録 |
PUT | 既存リソースの更新 |
DELETE | リソースの削除 |
PATCH | リソースの一部変更 |
HEAD | リソースのメタ情報の取得 |
たとえば、http://api.example.com/users というエンドポイントに対して、GETメソッドでアクセスした場合はユーザーの一覧取得、POSTメソッドでアクセスした場合はユーザーの新規登録を行うと良い。
検索のクエリパラメータ
タイムライン一覧の検索等では、データの全てを取得することは考えにくく、取得数の制限(limit)とどこから取得するかという情報が必要になる。
「どこから取得するか」に関しては、相対位置(offset)と絶対位置(since_id)の2つが考えられる。
相対位置では、最新情報からいくつかの情報を省いて取得する。これは、更新頻度の高いテーブルには適さない。また、データ数が増えるに連れて線形的に動作速度が落ちる。
絶対位置では、クライアントが最後に取得した情報のIDを利用する。
自分の情報へのエイリアス
自分の情報を取得するのに、http://api.example.com/users/123456 というURIの他に、http://api.example.com/users/self 等のURIを利用できるようにした方が良い。
OAuth2.0の利用
OAuth2.0は、標準化された、広く認知された仕組み。あるサービスのユーザー情報を第三者サービスに、情報源サービスのパスワードを第三者サービスに送信すること無く流すことが可能。
SSKDsに対するAPIデザイン
第三者サービスがホーム画面を用意することが分かっているなら、そこに必要な情報(ユーザー情報・タイムライン等)を全て一度に返すAPIを用意すべき。
1スクリーン1APIコール、1セーブ1APIコール。
HATEOAS と REST LEVEL3 API
REST LEVEL
(重大っぽい)誤植?
この本、割と誤植が多いので、重大っぽい誤植だけ挙げておく。初版第1刷です。
図2-6 OAuthの基本的な仕組み
3番と4番の矢印が逆。
0.3 Haskellでエラトステネスの篩
職場でエラトステネスの篩の話になって、ふと「関数型言語なら綺麗に書けそう」と思ったので、書いた。
一応、エラトステネスの篩とは、指定した範囲に含まれる素数を列挙するための高速アルゴリズムで、以下の様なものである。
1. 探索リストに2からnまでの整数を昇順で入れる。
2. 探索リストの先頭の数を素数リストに移動し、その倍数を探索リストから篩い落とす。
3. 上記の篩い落とし操作を探索リストの先頭値がxの平方根に達するまで行う。
4. 探索リストに残った数を素数リストに移動して処理終了。
今回書いたやつでは、探索リストが空になるまで探索を続けている。
remover :: Integer -> [Integer] -> [Integer] remover n ns = [x | x <- ns, x `mod` n /= 0] recursion :: [Integer] -> [Integer] recursion xs = case xs of [] -> [] (x:_) -> x : recursion (remover x xs) eratosthenes :: Integer -> [Integer] eratosthenes n = if n < 2 then error "Input bigger than 1." else let primes = [2..n] in recursion primes
removerは、nsからnの倍数の要素を落としたリストを返す。
recursionは、引数のリストが空になるまでremoverを適用し続ける。適用する際、引数のリストの先頭は戻り値のリストの元とする。
eratosthenesは、2~nまでに含まれる素数をリスト形式で出力する。primesに探索リストを作り、recursionを適用することで実現する。
で、もう少し簡略化出来そうだな~、と思って、以下の形に落ち着いた。
eratosthenes :: Integer -> [Integer] eratosthenes n = if n < 2 then error "Input bigger than 1." else let primes = [2..n] recursion ms = case ms of [] -> [] (m:_) -> m : recursion [x | x <- ms, x `mod` m /= 0] in recursion primes
case ms of辺りが少し汚いけど、再帰書くならどうしようもないかなぁ…。
リスト内包表記強い。
で、実際に実行してみる。
Prelude> :l eratosthenes.hs [1 of 1] Compiling Main ( eratosthenes.hs, interpreted ) Ok, modules loaded: Main. *Main> eratosthenes 10 [2,3,5,7] *Main> eratosthenes 100 [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] *Main> eratosthenes 0 *** Exception: Input bigger than 1. eratosthenes 10000000000000000000000000000000000000000000000 [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,...
これ、怖いのは最後の例で、アホみたいな引数を与えても迅速に結果を返してくる。
さすがに実行時間が速すぎる。遅延評価の賜物なのか?
久しぶりにHaskell触ると、割と楽しかった。
7.1 Unity2DでSTG作る日記 1日目
職場でUnityを使うことになったのと、個人的に作りたいものがあるので、いろいろテストしていく日記にしようと思う。日記なので、雑多な感じで書いていく。
最後にUnityを触ったのがカラオケ採点機を作った時で、完全に仕様とか忘れているので、色々と躓きながらの作業だった。
なお、使用しているのはUnity2D(v4.3.3f1)である。少し古い。
とりあえず、画像のインポート
「どうするんだっけ?」となっていたので調べた。プロジェクトフォルダのAssets内に置けばいいらしい。素材にしたい場合、Spriteとかいうものになるらしいので、Assetsフォルダの中にSpritesフォルダ作成。Spritesってなんなんだ。
で、以前DXライブラリで作っていたやつの素材フォルダを、すべてぶち込んだ。Unityに戻ると、正常に読み込まれた。平和に解決。
ドラッグ&ドロップでプレイヤー0のスプライトをSceneに突っ込む
画面上に追加された。Hierarchyに「0」とかいう名前のオブジェクトがある。あー、思い出してきた。
オブジェクトの名前をPlayerに変更。
当たり判定を付ける
Playerを選択して、InspectorからAdd Component -> Box Collider 2D。でも、これアクションゲームじゃないから、Colliderは要らないかもしれない。まぁ、よく分からんけど今は付けておこう。当たった瞬間をスイッチとして起こすイベントとか書けると思うし、たぶん。
操作できるようにする
サークルの後輩のスライドを頼った。Add Component -> New Script(C Sharp)。ファイル名はとりあえずPlayerにした。
スクリプトについて。デフォルトではAssets直下に配置されるので、Assets以下にScriptsフォルダを作り、ついでにSpritesフォルダと同様のフォルダ構成にして、Scripts/player/Player.csとした。
public class Player : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical"); this.transform.Translate(new Vector3(x, y)); } }
Input.GetAxisで入力を受け取って、this.transform.Translateで座標を更新するっぽい。詳しくは調査してない。
実行する。はやい。制御できん。スピードをつける。
public class Player : MonoBehaviour { public float Speed { get; private set; } // Use this for initialization void Start () { Speed = 0.2f; } // Update is called once per frame void Update () { float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical"); Vector3 v = new Vector3(x, y) * Speed; this.transform.Translate(v); } }
移動速度はいい感じになったけど、なんか、移動に慣性がついてるような…。
this.transform.Translateが悪いのかな?というわけで書き換える。
public class Player : MonoBehaviour { public float Speed { get; private set; } // Use this for initialization void Start () { Speed = 0.2f; } // Update is called once per frame void Update () { float inputX = Input.GetAxis("Horizontal"); float inputY = Input.GetAxis("Vertical"); Vector3 newPos = this.transform.position + new Vector3(inputX, inputY) * Speed; this.transform.position = newPos; } }
なんか、これでも慣性がついてる。ということは、Input.GetAxisの戻り値に慣性が付いてる可能性がある?
と、ここで時間が無くなったので終了。
Assets/Scenesフォルダを作り、test.unityとして現在のシーンを保存。てか、採点機作ってる時は1シーンだけでやってたし、遷移とかよく分かってないなぁ。
感想
そういえばUnityってこんなのだった。
ネット上の情報は割と偏っているので、書籍買ってちゃんと勉強したいなぁ。
0.2 OAuth認証(PINコード)
計算機科学実験及び演習4で、C#を用いたTwitter REST APIを利用するライブラリ制作を行った。
OAuth認証についてはライブラリを用いて良いということだったが、Twitter用にOAuth認証するライブラリは大体タイムライン取得やつぶやきも出来るようになってて、あまり意味が無いと感じたので、Google先生が提供しているOAuthBaseを利用して、割と一から認証処理を書いた。
おかげで、OAuth認証が何をやっているのかが分かったので、メモ書き程度の記事にしてみようと思う。
なお、今回扱うOAuth認証はPINコードを用いるもので、バージョンは1.0である。
OAuth1.0(PINコード)の流れ(見た目)
ブラウザアプリの場合は必要ないので、あまり見かけることはないが、数字を入力させる認証方法である。
具体的には、Twitterでは以下の様な流れになる。
- ブラウザ立ち上げ
- Twitterにログイン
- アプリと連携させるか選択
- PINコード(7桁の数字)を表示する
- アプリ内にPINコードを入力
- 認証完了
これが内部で何を行っているのかを探る。
OAuth1.0(PINコード)の流れ(中身)
まず、OAuth認証で重要なsignatureについて述べる。
signature
signatureはBase64形式のハッシュ値である。サーバとクライアントでこの値が一致していれば認証が通る。
signatureは、基礎値となるsignature_base文字列と、鍵となるkey文字列をHMAC-SHA1でハッシュ化したものをさらにBase64に変換した文字列となっている。
TwitterにおけるOAuth認証の流れ
request_token
ユーザは、アプリケーションの持つconsumer_keyおよびconsumer_secretしか情報を持っていない。よって、まずはaccess_tokenおよびaccess_token_secretを取得する必要がある。
そこで、access_tokenおよびaccess_token_secretを空の文字列としたsignatureをTwitter側に送信し、Twitterが生成したaccess_tokenおよびaccess_token_secretを受け取る。
signatureの受け渡しでは、同時に基礎文字列の材料も全てパラメータで受け渡す。つまり、パラメータさえ見ればsignature_baseは簡単に求められる。しかし、鍵の基となる情報は送受信しないため(Twitterとユーザが個人で持っている)、安全性が保証されるわけである。
この段階は、「そのアプリケーションに、渡したaccess_tokenおよびaccess_token_secretを持つ認証待ちユーザがいる」という意味を持つ。
TwitterログインとPINコード入力
ここで、ユーザにはTwitterにログインしてもらう。ログイン後、ユーザがアプリ連携を認めると、7桁のPINコードが表示される。アプリケーションは、このPINコードを受け取る。
access_token
先ほど受け取ったaccess_tokenおよびaccess_token_secretは、request_tokenおよびrequest_token_secretと呼ぶ。これらのリクエストトークンを用いて再びsignatureを求める。このsignatureと、先ほど受け取ったPINコードを、再びTwitterに送信し、Twitterから新しいaccess_tokenおよびaccess_token_secretを受け取る。これがAPIを叩くときのOAuth認証に使われるトークンとなる。
この段階は、「Twitterでログインされた、確かなユーザが認証された」という意味を持つ。
雑感
要するに、
- signature(signature_baseとkeyを使ったハッシュ)を照合させて認証する
- signature_baseは固定文字列とタイムスタンプとランダム文字列を用いて生成される
- keyはサーバ・クライアントがお互いローカルに保持する2つの文字列を用いて生成される
- 2つの鍵は、アプリケーションの鍵とユーザの鍵
- この2段階認証によって特定のアプリ上の特定のユーザが認証できる
というわけであるが、access_token_secretは最初の一回はサーバ側からクライアント側に送信される必要があるわけで、少し微妙な認証方式だと思う。
Rubyでbot作ってた時は、意味もわからずconsumer_key・consumer_secret・access_token・access_token_secretを入力していたが、今回の実験でその利用法が分かって良かった。
全然関係ない話になるが、RSA暗号はこの「鍵配送問題」を解決した画期的な暗号である。次回の記事で解説しようと思う。