SalesforceがGoInstant買収してどうのこうのって話らしいので、GoInstant試してます。
GoInstantでユーザ認証するには外部の認証プロバイダ(facebook, salesforce, github, google, twitter)
を使ってOpenID Connectやら何やらで認証するか
自前の認証プロバイダ(と言っても普通のログイン機能を有するアプリ)で
JWTをGoInstantに投げ入れて認証します。
前者の場合はそれぞれのアプリケーション設定して
ClientIDとかSecretを設定してJS叩くだけで超簡単に実装できます(リファレンス)。
後者のJWT生成もGoInstantのライブラリ(Ruby、Java、PHP、node.js)があって
ライブラリのない言語の場合もJWT生成のライブラリを使えば、こちらも楽勝。
んで、PythonでチャレンジしようとJWT生成のライブラリをインストールしてみたけど
うまくいかなかったのでJWTの勉強がてら、自前で生成してみた。
import base64
import json
import hmac
import hashlib
def base64url_decode(input):
input += '=' * (4 - (len(input) % 4))
return base64.urlsafe_b64decode(input)
def base64url_encode(input):
return base64.urlsafe_b64encode(input).replace('=', '')
key = base64url_decode("Input Your App Key")
header = {
'typ':'JWT',
'alg':'HS256'
}
payload = {
'iss':'localhost',
'sub':'test@freedom-man.com',
'dn':'freedom-man@display',
'g' :None
}
header_payload = base64url_encode(json.dumps(header)) + "." + base64url_encode(json.dumps(payload))
sig = base64url_encode(hmac.new(key, header_payload, seed, hashlib.sha256).digest())
print seed + "." + sig
これでJWT生成はOK。
生成の流れとしては、ヘッダ(暗号化方式を記述)とクレーム(トークンのデータ)のそれぞれのJSON文字列を
urlsafeなbase64エンコードして、それをカンマでくっつけたものを
アプリケーション毎のキーでハッシュ作ってurlsafeなbase64エンコードしてSignatureを作る。
最後にヘッダ、クレーム、Signatureをカンマで連結(それぞれbase64エンコード)して終わり。
実際の実装はdjangoなりflaskなりでログイン認証した後に、認証ユーザに対する適切なJWTを作って
JSの変数にバインドして、GoInstantのJSでユーザプレゼンスを得るって感じになる。
Apex(force.com)だとこんな感じ。
/**
* JWT生成
*/
public static String createJWT(String username, String displayname) {
Map<String, String> header = new Map<String, String>{
'typ' => 'JWT',
'alg' => 'HS256'
};
Map<String, String> payload = new Map<String, String>{
'iss' => 'salesforce.com',
'sub' => username,
'dn' => displayname,
'g' => null
};
String key = 'Input Your App Key';
String target =
encodeUrlsafeBase64(Blob.valueOf(JSON.serialize(header))) + '.' +
encodeUrlsafeBase64(Blob.valueOf(JSON.serialize(payload)));
String signature =
encodeUrlsafeBase64(Crypto.generateMac('HmacSha256', Blob.valueOf(target), decodeUrlsafeBase64(key)));
return target + '.' + signature;
}
/**
* base64urlエンコード
*/
public static String encodeUrlsafeBase64(Blob target) {
String ret = EncodingUtil.base64Encode(target);
ret = ret.replace('+', '-');
ret = ret.replace('/', '_');
ret = ret.replace('=', '');
return ret;
}
/**
* base64urlデコード
*/
public static Blob decodeUrlsafeBase64(String target) {
String ret = target;
ret = ret.replace('-', '+');
ret = ret.replace('_', '/');
return EncodingUtil.base64Decode(ret);
}
Salesforceの場合、ログイン認証は既にWebアプリとして持っているため
ログインユーザに見せるVFページでJWTを発行すれば、GoInstant内でもユーザプレゼンスが確保されます。