##<APIでアクセスしてみる> のエントリーでAPIを叩きながら触ってみて、Personium の大きな構造は把握できたと思います。「Personium は PDS」って言うくらいなのですから、ファイルやDBへのアクセスができなくてはいけません… これからのいくつかのエントリーで、そんなキモの機能について理解を深めてみましょう。
Personium では、ユーザーのパーソナルな情報をBoxに溜め込む構造になっているのは、これまでのエントリーで説明しました。
そしてユーザーもしくはユーザー以外の事業者が提供するアプリケーションがこのBoxと紐づけられた状態で、アプリケーションがインストールされることとなり、アプリからはこのBox内にストアされたデータにしかアクセスできない構造です。
もし、この辺の理解が「ちょっと、あやふやなだなぁ…」というような場合は、<ざっくりとPersoniumとは> を、一度確認してみてください。
さて、Personium では、データをストアするためには、WebDavやODataの"箱"を作りそこにデータを収めるような仕組みとなっています。っがドキュメントを探ってもここを明確に記載しているものが… あまり記憶がなく、ドキュメント中には以下が当てはまるくらいでしょうか??
私が明確に「WebDavやODataの"箱"を作りそこにデータを収めるような仕組みとなっている」という認識ができたのは、ドキュメントではなく「ある異邦人」さんの「技術メモ」を認めた ブログ でした!!
そこに、以下のように記載されていました…
personiumは、アプリケーションが扱うデータというものは「木構造のディレクトリ構造をもったファイルシステム的なもの」か「リレーショナルデータ的なもの」の2種類でほぼ事足りるかなぁという仮説に立っています。それで、personiumのアプリケーション毎のデータ空間はWebDAVの空間なのですが、そこにODataの空間が切れるようにして2種類のデータを扱えるようにしています。
なにやら、この「ある異邦人」さんは"扱えるようにしています"とか、「私がそう決めたんです」的な表現で、ちょっと偉そうな書き方をしていますね… たぶんPersoniumに携わるそうとうエライ方なんだと想像されます。
まぁドキュメントのように事務的に「書いてあることに意義がある」記載方法と違い、このような経緯までが把握できると、理解もできますし記憶も深くキザまれます。
私は Personium に興味を持った早いタイミングで、この ブログ を読んでいたので把握できていたのですが、ドキュメントを読む限りでは、若干想像を膨らませる必要があるかもしれません。
※追記(2019/03/20)
後日、『データの管理』 というドキュメントも見つけました…
#####またもや、ドキュメントのクォリティについて軽くdisったところで、そろそろ本題に進みましょう。
##1.環境の整理
まずはBoxを作らないといけないようですね。
<APIでアクセスしてみる> で利用したCellやAccount・Roleを流用し、環境を整えましょう。
しかしその前に、ここでまた一つ混乱するポイントを皆さんにインプットします。それは…
「セルを作成すると(自動的に)"隠しBOX"である"__"ボックスが作成されています」
<APIでアクセスしてみる> でも、以下の画像のように、"__ ボックスにひも付いている"とか、シレ〜と記載しています。
そしてこの"__"ボックスは、[main]ボックスと呼ばれる場合もあります。
「アプリセル」と呼ばれるアプリケーションのプログラムが配置される特殊なセルの場合、(パーソナル)データ以外の全てがこの"__"ボックス内に保持する用途として利用されます。
(この辺が本当に難しく… 私も全然理解が追いついていません。)
####既存の環境の整理
項目 | 値 |
---|---|
ユニット | https://personium.takky.org |
セル | admincell |
アカウント | user |
ロール | adminrole |
コンテンツ(ACL) | profile.json (read) |
[ ユニット:https://personium.takky.org ]
∟ [ セル:admincell ]
∟ [ ボックス:__ ]
∟ [ ロール:adminrole ]
∟[ アカウント:user ]
∟[ コンテンツ:profile.json ]
∟[ ACL:adminrole - read ]
##2.WebDavを触るための環境の整備
以下の内容でWebDavコレクション(ディレクトリ)を作成しましょう。
項目 | 値 | 処理 |
---|---|---|
ユニット | https://personium.takky.org | 無し |
セル | usercell | 有り |
ボックス | userbox | 有り |
アカウント | user | 無し |
ロール | userrole | 有り |
コレクション(ACL) | WebDavContents (read, write) | 有り |
セルの作成からACL付与までは、ユニット管理者で操作しましょう。
まずはトークンの取得
$ curl "https://personium.takky.org/unitadmin/__token" \
-X POST -i \
-d "grant_type=password&username={{unitAdminUser}}&password={{unitAdminPassword}}&p_target=https://personium.takky.org/" \
-H "Content-Type: application/x-www-form-urlencoded"
HTTP/1.1 200
Date: Mon, 18 Mar 2019 10:46:29 GMT
Content-Type: application/json
Content-Length: 4378
Connection: keep-alive
Location: https://personium.takky.org/__token
X-Personium-Version: 1.7.4
Server: Personium
{
"access_token":"{{unitAdminToken}}",
"refresh_token_expires_in":86400,
"refresh_token":"{{refreshToken}}",
"p_target":"https:\/\/personium.takky.org\/",
"token_type":"Bearer",
"expires_in":3600
}
##3.セル(usercell)を作成します。
$ curl "https://personium.takky.org/__ctl/Cell" \
-X POST -i \
-d "{\"Name\":\"usercell\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 201
Date: Mon, 18 Mar 2019 10:49:14 GMT
Content-Type: application/json
Content-Length: 247
Connection: keep-alive
Location: https://personium.takky.org/__ctl/Cell('usercell')
DataServiceVersion: 2.0
ETag: W/"1-1552906154394"
X-Personium-Version: 1.7.4
Server: Personium
{
"d":{
"results":{
"__metadata":{
"uri":"https:\/\/personium.takky.org\/__ctl\/Cell('usercell')",
"etag":"W\/\"1-1552906154394\"","type":"UnitCtl.Cell"
},
"Name":"usercell",
"__published":"\/Date(1552906154394)\/",
"__updated":"\/Date(1552906154394)\/"
}
}
}
##4.usercell セル内にボックス(userbox)を作成
$ curl "https://personium.takky.org/usercell/__ctl/Box" \
-X POST -i \
-d "{\"Name\":\"userbox\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 201
Date: Mon, 18 Mar 2019 10:56:49 GMT
Content-Type: application/json
Content-Length: 267
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Box('userbox')
DataServiceVersion: 2.0
ETag: W/"1-1552906609545"
X-Personium-Version: 1.7.4
Server: Personium
{
"d":{
"results":{
"__metadata":{
"uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Box('userbox')",
"etag":"W\/\"1-1552906609545\"",
"type":"CellCtl.Box"
},
"Name":"userbox",
"Schema":null,
"__published":"\/Date(1552906609545)\/",
"__updated":"\/Date(1552906609545)\/"
}
}
}
「HTTP/1.1 201 」 ここまで、順調ですね!!
##5.userboxボックス内にコレクション(WebDavContents)を作成
さて! ここからが本番の、WebDavコレクションの作成です。
とはいえ、これまでと何ら変わりません。
参考のドキュメントは、『WebDAV モデル』 で良いでしょうかね?
メソッドはこれまで利用したのとは少し違い「MKCOL」を利用するらしいです。
uriは、curl "https://personium.takky.org/{{cell}}/{{box}}/{{collection}}" のように
すれば良さそうです。
bodyには以下のようなXMLを記載する必要があるのですが、コレクションを作成する場合はこのままで良いようなので、そのまま利用します。
(リソースタイプは"collection"ですよ。ということが表現されているようです)
<?xml version=\"1.0\" encoding=\"utf-8\"?><D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:set></D:mkcol>
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X MKCOL -i \
-d "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:set></D:mkcol>" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 201
Date: Mon, 18 Mar 2019 11:06:53 GMT
Content-Length: 0
Connection: keep-alive
ETag: "1-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium
エラーはありません!!
次に、作成したWebDavコレクションを確認しましょう。
usercell セルの userbox ボックス内にコレクションを作成したので、「userbox」を指定し確認してみましょう。
$ curl "https://personium.takky.org/usercell/userbox" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:1' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 207
Date: Mon, 18 Mar 2019 11:23:18 GMT
Content-Type: application/xml
Content-Length: 1238
Connection: keep-alive
ETag: "1-1552907213232"
X-Personium-Version: 1.7.4
Server: Personium
<multistatus xmlns="DAV:">
<response>
<href>https://personium.takky.org/usercell/userbox</href>
<propstat>
<prop>
<creationdate>2019-03-18T11:06:53.232+0000</creationdate>
<getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
<resourcetype>
<collection/>
</resourcetype>
<acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
<propstat>
<prop>
<creationdate>2019-03-18T11:06:53.235+0000</creationdate>
<getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
<resourcetype>
<collection/>
</resourcetype>
<acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
「/userbox」と「/userbox/WebDavContents」の2つが出力されています。
userbx も WebDavContents も同等の扱いになっています。 ナンでやねん!!
#####実は、Personiumのオブジェクト全体が WebDav をベースに構成されているんです!
なので簡単に言うと、BoxもWebDavのディレクトリなんですね…
そして先ほど確認のために実行したコマンドには、"-H 'Depth:1'"とヘッダーにパラメータが与えられています。どんなコレクションが存在するかを取得する場合は、一つ上の階層を対象に'Depth:1'を指定し、ピンポイントでの存在の確認は、対象コレクションに対し'Depth:0'で取得するのが良いのかもしれません。
ヘッダ名 | 概要 | 有効値 | 必須 |
---|---|---|---|
Depth | 取得するリソースの階層 | 0:対象のリソース自身 1:対象のリソースとそれの直下のリソース |
○ |
ピンポイントで確認
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 207
Date: Mon, 18 Mar 2019 11:45:23 GMT
Content-Type: application/xml
Content-Length: 647
Connection: keep-alive
ETag: "1-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium
<multistatus xmlns="DAV:">
<response>
<href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
<propstat>
<prop>
<creationdate>2019-03-18T11:06:53.235+0000</creationdate>
<getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
<resourcetype>
<collection/>
</resourcetype>
<acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
OKですね!!
では、存在しないコレクション(WebDavContents2)をピンポイントで確認すると…
404が返ってきます。 404なんですね…
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents2" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 404
Date: Mon, 18 Mar 2019 11:49:51 GMT
Content-Type: application/json
Content-Length: 142
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium
{
"code":"PR404-DV-0001",
"message":{
"lang":"en",
"value":"Resource not found. [https://personium.takky.org/usercell/userbox/WebDavContents2]."
}
}
#####WebDavコレクションの作成は完了です!
※ お小言…
なにやら、ユニットマネージャにアクセスすると、以下のようにBasic認証のダイアログが出るようになったんですよねぇ… たぶん Ver1.7.5 から。
でもダイアログの[キャンセル]でそのまま利用できるので、今回はこれ以上追求しません。
##6.ロール(userrole)の作成とアカウントのひも付けとACL付与
では、次はアカウントを作ってロールに権限を付与しましょう。
設定内容の振り返り
項目 | 値 | 処理 |
---|---|---|
ユニット | https://personium.takky.org | 無し |
セル | usercell | 有り |
ボックス | userbox | 有り |
アカウント | user | 無し |
ロール | userrole | 有り |
コレクション(ACL) | WebDavContents (read, write) | 有り |
ユーザー(user)を作成
$ curl "https://personium.takky.org/usercell/__ctl/Account" \
-X POST -i \
-d "{\"Name\":\"user\"}" \
-H "X-Personium-Credential:{{Password}}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 201
Date: Tue, 19 Mar 2019 04:54:48 GMT
Content-Type: application/json
Content-Length: 307
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Account('user')
DataServiceVersion: 2.0
ETag: W/"1-1552971288710"
X-Personium-Version: 1.7.4
Server: Personium
{
"d":{
"results":{
"__metadata":{
"uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Account('user')",
"etag":"W\/\"1-1552971288710\"","type":"CellCtl.Account"
},
"Name":"user",
"LastAuthenticated":null,
"Type":"basic",
"Cell":null,
"__published":"\/Date(1552971288710)\/",
"__updated":"\/Date(1552971288710)\/"
}
}
}
##7.userbox にひも付いたロール(userrole)を作成
「userbox にひも付いた」の意味は、ボックスをExportしたりImportしたりすることがあり、この時にロールも含めてExportできるようにするための機能となります。
「userbox にひも付いた」状態にするためには、Bodyに"_Box.Name:userbox"と指定します。
curl "https://personium.takky.org/usercell/__ctl/Role" \
-X POST -i \
-d "{\"Name\":\"userrole\",\"_Box.Name\":\"userbox\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 201
Date: Tue, 19 Mar 2019 05:17:09 GMT
Content-Type: application/json
Content-Length: 304
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Role(Name='userrole',_Box.Name='userbox')
DataServiceVersion: 2.0
ETag: W/"1-1552972629032"
X-Personium-Version: 1.7.4
Server: Personium
{
"d":{
"results":{
"__metadata":{
"uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Role(Name='userrole',_Box.Name='userbox')",
"etag":"W\/\"1-1552972629032\"",
"type":"CellCtl.Role"
},
"Name":"userrole",
"_Box.Name":"userbox",
"__published":"\/Date(1552972629032)\/",
"__updated":"\/Date(1552972629032)\/"
}
}
}
##8.アカウント(user)にロール(userrole)をひも付ける
前の項で「userbox にひも付いた」状態にしているので、この時のロールの指定にも"_Box.Name:userbox"を指定する必要があることに注意しましょう。
$ curl "https://personium.takky.org/usercell/__ctl/Role(Name='userrole',_Box.Name='userbox')/\$links/_Account" \
> -X POST -i \
> -d "{\"uri\":\"https://personium.takky.org/usercell/__ctl/Account('user')\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 204
Date: Tue, 19 Mar 2019 05:31:07 GMT
Connection: keep-alive
DataServiceVersion: 2.0
X-Personium-Version: 1.7.4
Server: Personium
##9.コレクション(WebDavContents)に対してロール(userrole)にACL(read, write)を付与する
$ url 'https://personium.takky.org/usercell/userbox/WebDavContents' \
-X ACL -i \
-d '<D:acl xmlns:D="DAV:" xmlns:p="urn:x-personium:xmlns" xml:base="https://personium.takky.org/usercell/__role/userbox/"><D:ace><D:principal><D:href>userrole</D:href></D:principal><D:grant><D:privilege><p:read/></D:privilege><D:privilege><p:write/></D:privilege></D:grant></D:ace></D:acl>' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"
HTTP/1.1 200
Date: Tue, 19 Mar 2019 08:47:48 GMT
Content-Length: 0
Connection: keep-alive
ETag: "5-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium
イケたみたいですね!!
read も write も付与したいので、以下のように指定するのがポイント。
「 <D:privilege><p:read/></D:privilege><D:privilege><p:write/></D:privilege> 」
##10.コレクション(WebDavContents)をピンポイントで参照(read)
まずはユーザー(user)のトークンの取得
$ curl "https://personium.takky.org/usercell/__token" \
-X POST -i \
-d "grant_type=password&username={{userName}}&password={{userPassword}}" \
-H "Content-Type: application/x-www-form-urlencoded"
HTTP/1.1 200
Date: Tue, 19 Mar 2019 08:27:24 GMT
Content-Type: application/json
Content-Length: 331
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium
{
"access_token":"{{user_token}}",
"refresh_token_expires_in":86400,
"refresh_token":"{{refresh_token}}",
"token_type":"Bearer",
"expires_in":3600
}
そして確認。
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"
HTTP/1.1 207
Date: Tue, 19 Mar 2019 08:56:30 GMT
Content-Type: application/xml
Content-Length: 528
Connection: keep-alive
ETag: "7-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium
<multistatus xmlns="DAV:">
<response>
<href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
<propstat>
<prop>
<creationdate>2019-03-18T11:06:53.235+0000</creationdate>
<getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
<resourcetype>
<collection/>
</resourcetype>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
ユーザー(user)で、コレクション(ディレクトリ)をreadできました。
##11.オブジェクト(profilejson)の作成
コレクション(WebDavContents)配下に配置するファイルを作成します。
<APIでアクセスしてみる> のエントリーでも作成した、profile.json を作成しましょう。
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents/profile.json" \
-X PUT -i \
-d "{\"DisplayName\":\"<APIでアクセスしてみる>\",\"Description\": \"<APIでアクセスしてみる>のサンプルで利用するファイル\",\"Image\": \"data:image/png;base64,{{Image}}"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"
HTTP/1.1 100 Continue
HTTP/1.1 201
Date: Tue, 19 Mar 2019 09:04:59 GMT
Content-Length: 0
Connection: keep-alive
ETag: "1-1552986299484"
X-Personium-Version: 1.7.4
Server: Personium
イケましたね…
##12.ファイル(profile.json)の確認
$ curl "https://personium.takky.org/usercell/userbox/WebDavContents/profile.json" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"
HTTP/1.1 200
Date: Tue, 19 Mar 2019 09:08:43 GMT
Content-Type: application/x-www-form-urlencoded
Content-Length: 32568
Connection: keep-alive
ETag: "1-1552986299484"
Accept-Ranges: bytes
X-Personium-Version: 1.7.4
Server: Personium
{
"DisplayName":"<APIでアクセスしてみる>",
"Description": "<APIでアクセスしてみる>のサンプルで利用するファイル",
"Image": "data:image/png;base64,{{Image}}"
}
ファイルの内容である、"DisplayName" "Description" "Image" が取得できました。
想定通りです。
####WebDavコレクション(ディレクトリ)の作成と、ファイルの登録・参照が完了です!
###最後に
WebDavは… Personium の骨格とも言って良いベースの規格です。WebDavの空間上に Personium が乗っかっている感じです。なのでこのAPIを間違ってしまうと… とんでもない場所にファイルを作成してしまったり、アプリケーションに対して付与したACLが、Boxに影響してしまうような可能性も否定はできません。
そして、あるオブジェクトに付与したACLは、そのオブジェクトの配下のオブジェクトに、暗黙的に適用されてしまう仕様となっています。
上記のような仕様を把握した上で、適切なディレクトリ構造で適切なACL設定をするよう心がける必要があり、最悪の場合には公開してはいけないユーザー(ロール)に、パーソナル情報がダダ漏れする危険性もあります。
慎重な設計・コーディングを心がけてください。
本当は… このエントリでODataなどについても記載する想定だったのですが、思いの外 WebDav だけでそれなりの長編になってしまったので、OData・ExtRoleなどについては、この後のエントリで展開します。
####メニュー
-
10<セルとボックスについて理解する>
-
11<ホームアプリを触ってみる>
-
12<ユニットマネージャって便利じゃん>
-
13<テンプレートアプリってなんぞや>
-
14<自分のアプリケーション>