回答編集履歴
42
追記
test
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
**<下記は「試みたものの、結果としてはうまくいなかった例」になりますが、試行の過程として残しています。修正後の内容は、後述の「追記2」を参照してください>**
|
2
|
+
また、以下は、Amazon SP-API上での検証ではなく、他の一般的なOAuth2.0アプリケーションでの検証になります。
|
3
|
+
|
4
|
+
|
2
5
|
コピー元のスクリプトに doGet() を実装してWebアプリとしてデプロイし、コピー先からコピー元に対して、認証に必要な処理を呼び出せるようにしてはいかがでしょうか。
|
3
6
|
|
4
7
|
+ DEPLOY_URL は、一度コピー元をデプロイして確定してしまえば、変更がない限りコピー先で変更する必要はありません。(コピー先ファイルごとのデプロイURLに変える必要はありません。)
|
41
test
CHANGED
@@ -224,8 +224,8 @@
|
|
224
224
|
# 追記
|
225
225
|
|
226
226
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
227
|
-
+ ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
227
|
+
+ ①originalを所有(作成)しているGoogleアカウント**以外**のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
228
|
-
(①[オリジナル]を所有(作成)しているアカウント
|
228
|
+
(①[オリジナル]を所有(作成)しているGoogleアカウントであれば ②[コピー]のshowDialogを実行しても問題なく認証フローを完了できる)
|
229
229
|
これは、オリジナルとコピー両方公開ファイルにしても変わりません。
|
230
230
|
(おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
|
231
231
|
|
40
test
CHANGED
@@ -225,6 +225,7 @@
|
|
225
225
|
|
226
226
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
227
227
|
+ ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
228
|
+
(①[オリジナル]を所有(作成)しているアカウントが ②[コピー]を実行する場合は認証フローを完了できる)
|
228
229
|
これは、オリジナルとコピー両方公開ファイルにしても変わりません。
|
229
230
|
(おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
|
230
231
|
|
39
test
CHANGED
@@ -224,12 +224,13 @@
|
|
224
224
|
# 追記
|
225
225
|
|
226
226
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
227
|
-
+ ①を所有(作成)しているGoogleアカウント以外のアカウントが
|
227
|
+
+ ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
228
|
-
これは、
|
228
|
+
これは、オリジナルとコピー両方公開ファイルにしても変わりません。
|
229
229
|
(おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
|
230
230
|
|
231
|
+
一方、一部ではうまく行っています。
|
231
|
-
+ ①での認証・認可後、
|
232
|
+
+ ①[オリジナル]での認証・認可後、オリジナルを所有(作成)しているアカウント以外のアカウントが ②[コピー]を利用して①[オリジナル]からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは可能。
|
232
|
-
+ ①
|
233
|
+
+ ①からもらったアクセストークンが揮発した場合でも、①から自動的に更新後のアクセストークンを取得できる。
|
233
234
|
|
234
235
|
したがって、少なくとも最初の認証・認可フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
235
236
|
|
38
test
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
+
**<下記は「試みたものの、結果としてはうまくいなかった例」になりますが、試行の過程として残しています。修正後の内容は、後述の「追記2」を参照してください>**
|
1
|
-
|
2
|
+
コピー元のスクリプトに doGet() を実装してWebアプリとしてデプロイし、コピー先からコピー元に対して、認証に必要な処理を呼び出せるようにしてはいかがでしょうか。
|
2
3
|
|
3
4
|
+ DEPLOY_URL は、一度コピー元をデプロイして確定してしまえば、変更がない限りコピー先で変更する必要はありません。(コピー先ファイルごとのデプロイURLに変える必要はありません。)
|
4
5
|
|
37
test
CHANGED
@@ -225,7 +225,7 @@
|
|
225
225
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
226
|
+ ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
227
227
|
これは、①と②両方公開ファイルにしても変わりません。
|
228
|
-
(おそらくGASまたはO
|
228
|
+
(おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
|
229
229
|
|
230
230
|
+ ①での認証・認可後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
231
231
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
36
test
CHANGED
@@ -337,5 +337,5 @@
|
|
337
337
|
}
|
338
338
|
```
|
339
339
|
|
340
|
-
ただし、現状のコード
|
340
|
+
ただし、現状の単純なコードでは、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(GET時のパラメータに特別なトークンが埋め込まれていないとアクセストークンを発行できないようにする等)を実装することが必要です。
|
341
|
-
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secret
|
341
|
+
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだと認証に必要なclient_id や client_secret まで利用者セラーに知られてしまうのが問題だと思います)
|
35
test
CHANGED
@@ -337,5 +337,5 @@
|
|
337
337
|
}
|
338
338
|
```
|
339
339
|
|
340
|
-
ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(
|
340
|
+
ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(GET時のパラメータに特別なトークンが埋め込まれていないとアクセストークンを発行できないようにする等)が別途必要かもしれません。
|
341
341
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)
|
34
test
CHANGED
@@ -223,14 +223,14 @@
|
|
223
223
|
# 追記
|
224
224
|
|
225
225
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
|
-
+ ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認
|
226
|
+
+ ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
227
227
|
これは、①と②両方公開ファイルにしても変わりません。
|
228
228
|
(おそらくGASまたはOauth2の仕組み上不可避と思われます)
|
229
229
|
|
230
|
-
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
230
|
+
+ ①での認証・認可後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
231
231
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
232
232
|
|
233
|
-
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
233
|
+
したがって、少なくとも最初の認証・認可フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
234
234
|
|
235
235
|
|
236
236
|
|
@@ -238,8 +238,8 @@
|
|
238
238
|
|
239
239
|
# 追記2
|
240
240
|
結局、運用方針としては、下記のように①と②を分離し、
|
241
|
-
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
241
|
+
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証・認可を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
242
|
-
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
242
|
+
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証・認可フローは不要)
|
243
243
|
というのが現実的かもしれませんね。
|
244
244
|
|
245
245
|
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
@@ -293,7 +293,7 @@
|
|
293
293
|
|
294
294
|
②改
|
295
295
|
実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。
|
296
|
-
利用者セラーは認証フローを行わない前提のため、showDialogは①へ移動した。
|
296
|
+
利用者セラーは認証・認可フローを行わない前提のため、showDialogは①へ移動した。
|
297
297
|
こちらは特にデプロイする必要はない。
|
298
298
|
```js
|
299
299
|
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
33
test
CHANGED
@@ -223,8 +223,10 @@
|
|
223
223
|
# 追記
|
224
224
|
|
225
225
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
|
-
+ ①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
226
|
+
+ ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
227
227
|
これは、①と②両方公開ファイルにしても変わりません。
|
228
|
+
(おそらくGASまたはOauth2の仕組み上不可避と思われます)
|
229
|
+
|
228
230
|
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
229
231
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
230
232
|
|
32
test
CHANGED
@@ -229,8 +229,11 @@
|
|
229
229
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
230
230
|
|
231
231
|
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
232
|
-
|
233
|
-
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
|
234
237
|
# 追記2
|
235
238
|
結局、運用方針としては、下記のように①と②を分離し、
|
236
239
|
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
31
test
CHANGED
@@ -223,7 +223,7 @@
|
|
223
223
|
# 追記
|
224
224
|
|
225
225
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
|
-
|
226
|
+
+ ①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避と思われます)
|
227
227
|
これは、①と②両方公開ファイルにしても変わりません。
|
228
228
|
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
229
229
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
30
test
CHANGED
@@ -223,14 +223,16 @@
|
|
223
223
|
# 追記
|
224
224
|
|
225
225
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
|
-
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
226
|
+
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避)
|
227
227
|
これは、①と②両方公開ファイルにしても変わりません。
|
228
228
|
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
229
229
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
230
230
|
|
231
231
|
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
232
232
|
|
233
|
+
---
|
234
|
+
# 追記2
|
233
|
-
運用方針として、下記のように①と②を分離し、
|
235
|
+
結局、運用方針としては、下記のように①と②を分離し、
|
234
236
|
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
235
237
|
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
236
238
|
というのが現実的かもしれませんね。
|
29
test
CHANGED
@@ -330,5 +330,5 @@
|
|
330
330
|
}
|
331
331
|
```
|
332
332
|
|
333
|
-
ただし、現状のコードだと、DEPLOY_URLを知られてしまう
|
333
|
+
ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(post時に別のトークンを埋め込んで識別する等)が別途必要かもしれません。
|
334
334
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)
|
28
test
CHANGED
@@ -331,4 +331,4 @@
|
|
331
331
|
```
|
332
332
|
|
333
333
|
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
334
|
-
(
|
334
|
+
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)
|
27
test
CHANGED
@@ -230,15 +230,13 @@
|
|
230
230
|
|
231
231
|
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
232
232
|
|
233
|
-
運用方針として、①と②を分離し、
|
233
|
+
運用方針として、下記のように①と②を分離し、
|
234
234
|
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
235
235
|
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
236
236
|
というのが現実的かもしれませんね。
|
237
237
|
|
238
238
|
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
239
|
-
|
240
|
-
|
239
|
+
|
241
|
-
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
242
240
|
|
243
241
|
①改(認証・認可用ファイル。showDialogを元に戻した)。デプロイし、デプロイURLを②改に記載する。
|
244
242
|
```js
|
@@ -331,4 +329,6 @@
|
|
331
329
|
console.log(orders);
|
332
330
|
}
|
333
331
|
```
|
332
|
+
|
334
|
-
|
333
|
+
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
334
|
+
(ただし、この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)
|
26
test
CHANGED
@@ -240,7 +240,7 @@
|
|
240
240
|
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
241
241
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
242
242
|
|
243
|
-
①改(認証・認可用ファイル。showDialogを元に戻した)
|
243
|
+
①改(認証・認可用ファイル。showDialogを元に戻した)。デプロイし、デプロイURLを②改に記載する。
|
244
244
|
```js
|
245
245
|
AUTH_ENDPOINT = 'https://XXX';
|
246
246
|
TOKEN_ENDPOINT = 'https://YYY';
|
@@ -286,7 +286,10 @@
|
|
286
286
|
```
|
287
287
|
|
288
288
|
|
289
|
+
②改
|
290
|
+
実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。
|
289
|
-
|
291
|
+
利用者セラーは認証フローを行わない前提のため、showDialogは①へ移動した。
|
292
|
+
こちらは特にデプロイする必要はない。
|
290
293
|
```js
|
291
294
|
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
292
295
|
|
25
test
CHANGED
@@ -286,7 +286,7 @@
|
|
286
286
|
```
|
287
287
|
|
288
288
|
|
289
|
-
②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
|
289
|
+
②改’(実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。セラーは認証フローを行わない前提のため、showDialogは①へ移動)
|
290
290
|
```js
|
291
291
|
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
292
292
|
|
24
test
CHANGED
@@ -89,169 +89,6 @@
|
|
89
89
|
output.setContent(JSON.stringify(content));
|
90
90
|
return output;
|
91
91
|
}
|
92
|
-
```
|
93
|
-
|
94
|
-
-----
|
95
|
-
# 説明
|
96
|
-
|
97
|
-
上記は、実質的には下記の2つのコードを合体したものになります。
|
98
|
-
① original.gs
|
99
|
-
・認証・認可の処理を行う専用のファイル。
|
100
|
-
・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
|
101
|
-
```js
|
102
|
-
AUTH_ENDPOINT = 'https://XXX';
|
103
|
-
TOKEN_ENDPOINT = 'https://YYY';
|
104
|
-
CLIENT_ID = 'AAA';
|
105
|
-
CLIENT_SECRET = 'BBB';
|
106
|
-
APP_ID = 'CCC';
|
107
|
-
|
108
|
-
// OAuth2ライブラリ使用
|
109
|
-
function getService() {
|
110
|
-
略
|
111
|
-
}
|
112
|
-
|
113
|
-
function authCallback(request) {
|
114
|
-
略
|
115
|
-
}
|
116
|
-
|
117
|
-
function doGet(e) {
|
118
|
-
if (e.parameter.authmode)
|
119
|
-
return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
|
120
|
-
|
121
|
-
if (getService.hasAccess())
|
122
|
-
return toJson({ authorized: true, token: getService.getAccessToken() })
|
123
|
-
|
124
|
-
return toJson({ authorized: false })
|
125
|
-
}
|
126
|
-
|
127
|
-
function toJson(content) {
|
128
|
-
略
|
129
|
-
}
|
130
|
-
```
|
131
|
-
|
132
|
-
② copy.gs
|
133
|
-
・実際の処理を行うファイル
|
134
|
-
```js
|
135
|
-
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
136
|
-
|
137
|
-
/**
|
138
|
-
* 認証用ダイアログ(html)表示
|
139
|
-
* セラーセントラルの認証URLへリンクさせる
|
140
|
-
*/
|
141
|
-
function showDialog() {
|
142
|
-
const respjson = UrlFetchApp.fetch(DEPLOY_URL + '?authmode=true').getContentText();
|
143
|
-
const response = JSON.parse(respjson);
|
144
|
-
const url = response.authorizationUrl;
|
145
|
-
const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
|
146
|
-
const html = HtmlService.createHtmlOutput(tag_text);
|
147
|
-
SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
|
148
|
-
}
|
149
|
-
|
150
|
-
/**
|
151
|
-
* アクセストークンを取得する。
|
152
|
-
*/
|
153
|
-
function getToken() {
|
154
|
-
const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
|
155
|
-
const response = JSON.parse(respjson);
|
156
|
-
if (response.authorized) {
|
157
|
-
return response.token;
|
158
|
-
} else {
|
159
|
-
return "UNAUTHORIZED"
|
160
|
-
}
|
161
|
-
}
|
162
|
-
```
|
163
|
-
|
164
|
-
上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
|
165
|
-
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
166
|
-
|
167
|
-
②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
|
168
|
-
この過程でアクセストークンを ①の中に保管しておきます。
|
169
|
-
|
170
|
-
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
171
|
-
|
172
|
-
-----
|
173
|
-
# 追記
|
174
|
-
|
175
|
-
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
176
|
-
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
177
|
-
これは、①と②両方公開ファイルにしても変わりません。
|
178
|
-
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
179
|
-
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
180
|
-
|
181
|
-
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
182
|
-
|
183
|
-
運用方針として、①と②を分離し、
|
184
|
-
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
185
|
-
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
186
|
-
というのが現実的かもしれませんね。
|
187
|
-
|
188
|
-
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
189
|
-
|
190
|
-
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
191
|
-
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
192
|
-
|
193
|
-
①改(認証・認可用ファイル。showDialogを元に戻した)
|
194
|
-
```js
|
195
|
-
AUTH_ENDPOINT = 'https://XXX';
|
196
|
-
TOKEN_ENDPOINT = 'https://YYY';
|
197
|
-
CLIENT_ID = 'AAA';
|
198
|
-
CLIENT_SECRET = 'BBB';
|
199
|
-
APP_ID = 'CCC';
|
200
|
-
|
201
|
-
// OAuth2ライブラリ使用
|
202
|
-
function getService() {
|
203
|
-
略
|
204
|
-
.setLock(LockService.getUserLock());
|
205
|
-
}
|
206
|
-
|
207
|
-
function authCallback(request) {
|
208
|
-
略
|
209
|
-
}
|
210
|
-
|
211
|
-
function doGet(e) {
|
212
|
-
if (e.parameter.authmode)
|
213
|
-
return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
|
214
|
-
|
215
|
-
if (getService.hasAccess())
|
216
|
-
return toJson({ authorized: true, token: getService.getAccessToken() })
|
217
|
-
|
218
|
-
return toJson({ authorized: false })
|
219
|
-
}
|
220
|
-
|
221
|
-
function toJson(content) {
|
222
|
-
略
|
223
|
-
}
|
224
|
-
|
225
|
-
/**
|
226
|
-
* 認証用ダイアログ(html)表示
|
227
|
-
* セラーセントラルの認証URLへリンクさせる
|
228
|
-
*/
|
229
|
-
function showDialog(){
|
230
|
-
const service = getService();
|
231
|
-
const url = service.getAuthorizationUrl();
|
232
|
-
const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
|
233
|
-
const html = HtmlService.createHtmlOutput(tag_text);
|
234
|
-
SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
|
235
|
-
}
|
236
|
-
```
|
237
|
-
|
238
|
-
|
239
|
-
②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
|
240
|
-
```js
|
241
|
-
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
242
|
-
|
243
|
-
/**
|
244
|
-
* アクセストークンを取得する。
|
245
|
-
*/
|
246
|
-
function getToken() {
|
247
|
-
const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
|
248
|
-
const response = JSON.parse(respjson);
|
249
|
-
if (response.authorized) {
|
250
|
-
return response.token;
|
251
|
-
} else {
|
252
|
-
return "UNAUTHORIZED"
|
253
|
-
}
|
254
|
-
}
|
255
92
|
|
256
93
|
/*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
|
257
94
|
* 下記は注文を取得する例。
|
@@ -279,3 +116,216 @@
|
|
279
116
|
}
|
280
117
|
```
|
281
118
|
|
119
|
+
-----
|
120
|
+
# 説明
|
121
|
+
|
122
|
+
上記は、実質的には下記の2つのコードを合体したものになります。
|
123
|
+
① original.gs
|
124
|
+
・認証・認可の処理を行う専用のファイル。
|
125
|
+
・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
|
126
|
+
```js
|
127
|
+
AUTH_ENDPOINT = 'https://XXX';
|
128
|
+
TOKEN_ENDPOINT = 'https://YYY';
|
129
|
+
CLIENT_ID = 'AAA';
|
130
|
+
CLIENT_SECRET = 'BBB';
|
131
|
+
APP_ID = 'CCC';
|
132
|
+
|
133
|
+
// OAuth2ライブラリ使用
|
134
|
+
function getService() {
|
135
|
+
略
|
136
|
+
}
|
137
|
+
|
138
|
+
function authCallback(request) {
|
139
|
+
略
|
140
|
+
}
|
141
|
+
|
142
|
+
function doGet(e) {
|
143
|
+
if (e.parameter.authmode)
|
144
|
+
return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
|
145
|
+
|
146
|
+
if (getService.hasAccess())
|
147
|
+
return toJson({ authorized: true, token: getService.getAccessToken() })
|
148
|
+
|
149
|
+
return toJson({ authorized: false })
|
150
|
+
}
|
151
|
+
|
152
|
+
function toJson(content) {
|
153
|
+
略
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
② copy.gs
|
158
|
+
・実際の処理を行うファイル
|
159
|
+
```js
|
160
|
+
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
161
|
+
|
162
|
+
/**
|
163
|
+
* 認証用ダイアログ(html)表示
|
164
|
+
* セラーセントラルの認証URLへリンクさせる
|
165
|
+
*/
|
166
|
+
function showDialog() {
|
167
|
+
const respjson = UrlFetchApp.fetch(DEPLOY_URL + '?authmode=true').getContentText();
|
168
|
+
const response = JSON.parse(respjson);
|
169
|
+
const url = response.authorizationUrl;
|
170
|
+
const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
|
171
|
+
const html = HtmlService.createHtmlOutput(tag_text);
|
172
|
+
SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* アクセストークンを取得する。
|
177
|
+
*/
|
178
|
+
function getToken() {
|
179
|
+
const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
|
180
|
+
const response = JSON.parse(respjson);
|
181
|
+
if (response.authorized) {
|
182
|
+
return response.token;
|
183
|
+
} else {
|
184
|
+
return "UNAUTHORIZED"
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
/*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
|
189
|
+
* 下記は注文を取得する例。
|
190
|
+
*/
|
191
|
+
function getOrders(){
|
192
|
+
const access_token = getToken(); // アクセストークンの取得
|
193
|
+
if (access_token==='UNAUTHORIZED) {
|
194
|
+
console.log('認証が完了していないためアクセストークンを取得できません。' +
|
195
|
+
管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
|
196
|
+
}
|
197
|
+
略
|
198
|
+
|
199
|
+
const end_point = 'https://sellingpartnerapi-eu.amazon.com';
|
200
|
+
略
|
201
|
+
const options = {
|
202
|
+
'method': 'GET',
|
203
|
+
'headers': {
|
204
|
+
'x-amz-access-token': access_token,
|
205
|
+
'x-amz-date': isoDate,
|
206
|
+
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
|
207
|
+
}
|
208
|
+
}
|
209
|
+
const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
|
210
|
+
console.log(orders);
|
211
|
+
}
|
212
|
+
```
|
213
|
+
|
214
|
+
上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
|
215
|
+
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
216
|
+
|
217
|
+
②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
|
218
|
+
この過程でアクセストークンを ①の中に保管しておきます。
|
219
|
+
|
220
|
+
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
221
|
+
|
222
|
+
-----
|
223
|
+
# 追記
|
224
|
+
|
225
|
+
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
226
|
+
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
227
|
+
これは、①と②両方公開ファイルにしても変わりません。
|
228
|
+
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
229
|
+
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
230
|
+
|
231
|
+
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
232
|
+
|
233
|
+
運用方針として、①と②を分離し、
|
234
|
+
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
235
|
+
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
236
|
+
というのが現実的かもしれませんね。
|
237
|
+
|
238
|
+
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
239
|
+
|
240
|
+
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
241
|
+
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
242
|
+
|
243
|
+
①改(認証・認可用ファイル。showDialogを元に戻した)
|
244
|
+
```js
|
245
|
+
AUTH_ENDPOINT = 'https://XXX';
|
246
|
+
TOKEN_ENDPOINT = 'https://YYY';
|
247
|
+
CLIENT_ID = 'AAA';
|
248
|
+
CLIENT_SECRET = 'BBB';
|
249
|
+
APP_ID = 'CCC';
|
250
|
+
|
251
|
+
// OAuth2ライブラリ使用
|
252
|
+
function getService() {
|
253
|
+
略
|
254
|
+
.setLock(LockService.getUserLock());
|
255
|
+
}
|
256
|
+
|
257
|
+
function authCallback(request) {
|
258
|
+
略
|
259
|
+
}
|
260
|
+
|
261
|
+
function doGet(e) {
|
262
|
+
if (e.parameter.authmode)
|
263
|
+
return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
|
264
|
+
|
265
|
+
if (getService.hasAccess())
|
266
|
+
return toJson({ authorized: true, token: getService.getAccessToken() })
|
267
|
+
|
268
|
+
return toJson({ authorized: false })
|
269
|
+
}
|
270
|
+
|
271
|
+
function toJson(content) {
|
272
|
+
略
|
273
|
+
}
|
274
|
+
|
275
|
+
/**
|
276
|
+
* 認証用ダイアログ(html)表示
|
277
|
+
* セラーセントラルの認証URLへリンクさせる
|
278
|
+
*/
|
279
|
+
function showDialog(){
|
280
|
+
const service = getService();
|
281
|
+
const url = service.getAuthorizationUrl();
|
282
|
+
const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
|
283
|
+
const html = HtmlService.createHtmlOutput(tag_text);
|
284
|
+
SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
|
285
|
+
}
|
286
|
+
```
|
287
|
+
|
288
|
+
|
289
|
+
②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
|
290
|
+
```js
|
291
|
+
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
292
|
+
|
293
|
+
/**
|
294
|
+
* アクセストークンを取得する。
|
295
|
+
*/
|
296
|
+
function getToken() {
|
297
|
+
const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
|
298
|
+
const response = JSON.parse(respjson);
|
299
|
+
if (response.authorized) {
|
300
|
+
return response.token;
|
301
|
+
} else {
|
302
|
+
return "UNAUTHORIZED"
|
303
|
+
}
|
304
|
+
}
|
305
|
+
|
306
|
+
/*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
|
307
|
+
* 下記は注文を取得する例。
|
308
|
+
*/
|
309
|
+
function getOrders(){
|
310
|
+
const access_token = getToken(); // アクセストークンの取得
|
311
|
+
if (access_token==='UNAUTHORIZED) {
|
312
|
+
console.log('認証が完了していないためアクセストークンを取得できません。' +
|
313
|
+
管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
|
314
|
+
}
|
315
|
+
略
|
316
|
+
|
317
|
+
const end_point = 'https://sellingpartnerapi-eu.amazon.com';
|
318
|
+
略
|
319
|
+
const options = {
|
320
|
+
'method': 'GET',
|
321
|
+
'headers': {
|
322
|
+
'x-amz-access-token': access_token,
|
323
|
+
'x-amz-date': isoDate,
|
324
|
+
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
|
325
|
+
}
|
326
|
+
}
|
327
|
+
const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
|
328
|
+
console.log(orders);
|
329
|
+
}
|
330
|
+
```
|
331
|
+
|
23
test
CHANGED
@@ -180,9 +180,9 @@
|
|
180
180
|
|
181
181
|
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
182
182
|
|
183
|
-
運用方針として、①と②を分離し
|
183
|
+
運用方針として、①と②を分離し、
|
184
|
-
+ ①は開発者/管理者が専有してメンテナンス(最初
|
184
|
+
+ ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
185
|
-
+ 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
185
|
+
+ 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
186
186
|
というのが現実的かもしれませんね。
|
187
187
|
|
188
188
|
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
22
test
CHANGED
@@ -185,7 +185,7 @@
|
|
185
185
|
+ 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
186
186
|
というのが現実的かもしれませんね。
|
187
187
|
|
188
|
-
crient_secret をむやみに
|
188
|
+
crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
|
189
189
|
|
190
190
|
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
191
191
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
21
test
CHANGED
@@ -201,6 +201,7 @@
|
|
201
201
|
// OAuth2ライブラリ使用
|
202
202
|
function getService() {
|
203
203
|
略
|
204
|
+
.setLock(LockService.getUserLock());
|
204
205
|
}
|
205
206
|
|
206
207
|
function authCallback(request) {
|
20
test
CHANGED
@@ -188,7 +188,7 @@
|
|
188
188
|
crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
|
189
189
|
|
190
190
|
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
191
|
-
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
|
191
|
+
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
|
192
192
|
|
193
193
|
①改(認証・認可用ファイル。showDialogを元に戻した)
|
194
194
|
```js
|
19
test
CHANGED
@@ -187,7 +187,7 @@
|
|
187
187
|
|
188
188
|
crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
|
189
189
|
|
190
|
-
ただし、DEPLOY_URLを知られてしまう
|
190
|
+
ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
|
191
191
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
|
192
192
|
|
193
193
|
①改(認証・認可用ファイル。showDialogを元に戻した)
|
18
test
CHANGED
@@ -177,15 +177,16 @@
|
|
177
177
|
これは、①と②両方公開ファイルにしても変わりません。
|
178
178
|
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
179
179
|
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
180
|
-
|
181
|
-
|
180
|
+
|
182
|
-
少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
181
|
+
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
182
|
+
|
183
|
-
①と②
|
183
|
+
運用方針として、①と②を分離してしまい、
|
184
|
-
+ ①は開発者
|
184
|
+
+ ①は開発者/管理者が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
|
185
185
|
+ 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
186
|
-
|
186
|
+
というのが現実的かもしれませんね。
|
187
187
|
|
188
188
|
crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
|
189
|
+
|
189
190
|
ただし、DEPLOY_URLを知られてしまうと勝手にいろいろできてしまうので、ユーザー管理のしくみは別途必要かもしれません。
|
190
191
|
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
|
191
192
|
|
17
test
CHANGED
@@ -175,14 +175,20 @@
|
|
175
175
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
176
176
|
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
177
177
|
これは、①と②両方公開ファイルにしても変わりません。
|
178
|
-
|
178
|
+
+ ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
179
|
-
|
179
|
+
+ ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
|
180
|
-
~~についてはまだ確認できていません。~~ →更新できているようです。
|
181
180
|
|
182
181
|
したがって、
|
183
182
|
少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
183
|
+
①と②の運用を完全に分離し、
|
184
|
-
①
|
184
|
+
+ ①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)
|
185
|
-
|
185
|
+
+ 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
|
186
|
+
、というのが現実的かもしれませんね。
|
187
|
+
|
188
|
+
crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
|
189
|
+
ただし、DEPLOY_URLを知られてしまうと勝手にいろいろできてしまうので、ユーザー管理のしくみは別途必要かもしれません。
|
190
|
+
(この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
|
191
|
+
|
186
192
|
①改(認証・認可用ファイル。showDialogを元に戻した)
|
187
193
|
```js
|
188
194
|
AUTH_ENDPOINT = 'https://XXX';
|
16
test
CHANGED
@@ -266,7 +266,7 @@
|
|
266
266
|
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
|
267
267
|
}
|
268
268
|
}
|
269
|
-
cons
|
269
|
+
const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
|
270
270
|
console.log(orders);
|
271
271
|
}
|
272
272
|
```
|
15
test
CHANGED
@@ -250,6 +250,10 @@
|
|
250
250
|
*/
|
251
251
|
function getOrders(){
|
252
252
|
const access_token = getToken(); // アクセストークンの取得
|
253
|
+
if (access_token==='UNAUTHORIZED) {
|
254
|
+
console.log('認証が完了していないためアクセストークンを取得できません。' +
|
255
|
+
管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
|
256
|
+
}
|
253
257
|
略
|
254
258
|
|
255
259
|
const end_point = 'https://sellingpartnerapi-eu.amazon.com';
|
14
test
CHANGED
@@ -182,3 +182,88 @@
|
|
182
182
|
したがって、
|
183
183
|
少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
184
184
|
①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)、利用者側には②を使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)、というのが現実的かもしれませんね。
|
185
|
+
|
186
|
+
①改(認証・認可用ファイル。showDialogを元に戻した)
|
187
|
+
```js
|
188
|
+
AUTH_ENDPOINT = 'https://XXX';
|
189
|
+
TOKEN_ENDPOINT = 'https://YYY';
|
190
|
+
CLIENT_ID = 'AAA';
|
191
|
+
CLIENT_SECRET = 'BBB';
|
192
|
+
APP_ID = 'CCC';
|
193
|
+
|
194
|
+
// OAuth2ライブラリ使用
|
195
|
+
function getService() {
|
196
|
+
略
|
197
|
+
}
|
198
|
+
|
199
|
+
function authCallback(request) {
|
200
|
+
略
|
201
|
+
}
|
202
|
+
|
203
|
+
function doGet(e) {
|
204
|
+
if (e.parameter.authmode)
|
205
|
+
return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
|
206
|
+
|
207
|
+
if (getService.hasAccess())
|
208
|
+
return toJson({ authorized: true, token: getService.getAccessToken() })
|
209
|
+
|
210
|
+
return toJson({ authorized: false })
|
211
|
+
}
|
212
|
+
|
213
|
+
function toJson(content) {
|
214
|
+
略
|
215
|
+
}
|
216
|
+
|
217
|
+
/**
|
218
|
+
* 認証用ダイアログ(html)表示
|
219
|
+
* セラーセントラルの認証URLへリンクさせる
|
220
|
+
*/
|
221
|
+
function showDialog(){
|
222
|
+
const service = getService();
|
223
|
+
const url = service.getAuthorizationUrl();
|
224
|
+
const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
|
225
|
+
const html = HtmlService.createHtmlOutput(tag_text);
|
226
|
+
SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
|
227
|
+
}
|
228
|
+
```
|
229
|
+
|
230
|
+
|
231
|
+
②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
|
232
|
+
```js
|
233
|
+
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
234
|
+
|
235
|
+
/**
|
236
|
+
* アクセストークンを取得する。
|
237
|
+
*/
|
238
|
+
function getToken() {
|
239
|
+
const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
|
240
|
+
const response = JSON.parse(respjson);
|
241
|
+
if (response.authorized) {
|
242
|
+
return response.token;
|
243
|
+
} else {
|
244
|
+
return "UNAUTHORIZED"
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
/*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
|
249
|
+
* 下記は注文を取得する例。
|
250
|
+
*/
|
251
|
+
function getOrders(){
|
252
|
+
const access_token = getToken(); // アクセストークンの取得
|
253
|
+
略
|
254
|
+
|
255
|
+
const end_point = 'https://sellingpartnerapi-eu.amazon.com';
|
256
|
+
略
|
257
|
+
const options = {
|
258
|
+
'method': 'GET',
|
259
|
+
'headers': {
|
260
|
+
'x-amz-access-token': access_token,
|
261
|
+
'x-amz-date': isoDate,
|
262
|
+
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
|
263
|
+
}
|
264
|
+
}
|
265
|
+
consr orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
|
266
|
+
console.log(orders);
|
267
|
+
}
|
268
|
+
```
|
269
|
+
|
13
test
CHANGED
@@ -181,4 +181,4 @@
|
|
181
181
|
|
182
182
|
したがって、
|
183
183
|
少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
184
|
-
①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス、利用者側に②を使ってもらう、というのが現実的かもしれま
|
184
|
+
①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)、利用者側には②を使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)、というのが現実的かもしれませんね。
|
12
test
CHANGED
@@ -176,6 +176,9 @@
|
|
176
176
|
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
177
177
|
これは、①と②両方公開ファイルにしても変わりません。
|
178
178
|
・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
179
|
-
・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるか
|
179
|
+
・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるか
|
180
|
+
~~についてはまだ確認できていません。~~ →更新できているようです。
|
180
181
|
|
182
|
+
したがって、
|
181
|
-
|
183
|
+
少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
184
|
+
①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス、利用者側に②を使ってもらう、というのが現実的かもしれまsね。
|
11
test
CHANGED
@@ -174,6 +174,7 @@
|
|
174
174
|
|
175
175
|
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
176
176
|
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
177
|
+
これは、①と②両方公開ファイルにしても変わりません。
|
177
178
|
・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
178
179
|
・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるかについてはまだ確認できていません。
|
179
180
|
|
10
追記
test
CHANGED
@@ -169,3 +169,12 @@
|
|
169
169
|
|
170
170
|
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
171
171
|
|
172
|
+
-----
|
173
|
+
# 追記
|
174
|
+
|
175
|
+
他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
|
176
|
+
・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
|
177
|
+
・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
|
178
|
+
・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるかについてはまだ確認できていません。
|
179
|
+
|
180
|
+
したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
|
9
test
CHANGED
@@ -8,7 +8,11 @@
|
|
8
8
|
|
9
9
|
+ セラーセントラルのAPI登録画面でのリダイレクトURIは、コピー元のcallbackから変更する必要はありません。
|
10
10
|
|
11
|
+
+ 複数ユーザーの同時アクセスに対応するためgetService関数の中でロックを設定しています。( [参照](https://github.com/googleworkspace/apps-script-oauth2#locking) )
|
12
|
+
※実際にはその他の処理でも複数ユーザーによる競合が想定される部分には、ロックをかける必要があるかもしれません。
|
11
13
|
DEPLOY_URLを追加しているほか、showDialog() も一部修正しています。
|
14
|
+
|
15
|
+
|
12
16
|
```js
|
13
17
|
AUTH_ENDPOINT = 'https://XXX';
|
14
18
|
他...
|
@@ -20,6 +24,7 @@
|
|
20
24
|
// OAuth2ライブラリ使用
|
21
25
|
function getService() {
|
22
26
|
略
|
27
|
+
.setLock(LockService.getUserLock()); // 複数ユーザーが同時にトークンをリフレッシュしようとする可能性があるためロックを設定。
|
23
28
|
}
|
24
29
|
|
25
30
|
/**
|
8
test
CHANGED
@@ -59,14 +59,14 @@
|
|
59
59
|
}
|
60
60
|
|
61
61
|
/**
|
62
|
-
* GETリクエスト時に呼ばれる。
|
62
|
+
* クライアントからGETリクエストを受けた時に呼ばれる。
|
63
63
|
* @return : JSON string
|
64
64
|
* 呼び出し元に「authmode」パラメータが存在する場合
|
65
65
|
* {"authorizationUrl : 認可URL}
|
66
66
|
* 呼び出し元に「authmode」パラメータが存在せず、認可済みの場合
|
67
67
|
* {"anthorized" : true, "token" : アクセストークン}
|
68
68
|
* 呼び出し元に「authmode」パラメータが存在せず、未認可の場合
|
69
|
-
* {"authorized" :
|
69
|
+
* {"authorized" : false}
|
70
70
|
*/
|
71
71
|
function doGet(e) {
|
72
72
|
if (e.parameter.authmode)
|
7
test
CHANGED
@@ -92,7 +92,7 @@
|
|
92
92
|
上記は、実質的には下記の2つのコードを合体したものになります。
|
93
93
|
① original.gs
|
94
94
|
・認証・認可の処理を行う専用のファイル。
|
95
|
-
・アクセストークンを保管するとともに、②からの要求に応じてトークンを渡す。
|
95
|
+
・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
|
96
96
|
```js
|
97
97
|
AUTH_ENDPOINT = 'https://XXX';
|
98
98
|
TOKEN_ENDPOINT = 'https://YYY';
|
6
test
CHANGED
@@ -91,6 +91,8 @@
|
|
91
91
|
|
92
92
|
上記は、実質的には下記の2つのコードを合体したものになります。
|
93
93
|
① original.gs
|
94
|
+
・認証・認可の処理を行う専用のファイル。
|
95
|
+
・アクセストークンを保管するとともに、②からの要求に応じてトークンを渡す。
|
94
96
|
```js
|
95
97
|
AUTH_ENDPOINT = 'https://XXX';
|
96
98
|
TOKEN_ENDPOINT = 'https://YYY';
|
@@ -123,6 +125,7 @@
|
|
123
125
|
```
|
124
126
|
|
125
127
|
② copy.gs
|
128
|
+
・実際の処理を行うファイル
|
126
129
|
```js
|
127
130
|
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
128
131
|
|
5
test
CHANGED
@@ -157,7 +157,6 @@
|
|
157
157
|
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
158
158
|
|
159
159
|
②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
|
160
|
-
( たとえば、showDialog関数内で取得している authorizationUrl のリダイレクト先は①になっています)
|
161
160
|
この過程でアクセストークンを ①の中に保管しておきます。
|
162
161
|
|
163
162
|
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
4
test
CHANGED
@@ -157,6 +157,7 @@
|
|
157
157
|
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
158
158
|
|
159
159
|
②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
|
160
|
+
( たとえば、showDialog関数内で取得している authorizationUrl のリダイレクト先は①になっています)
|
160
161
|
この過程でアクセストークンを ①の中に保管しておきます。
|
161
162
|
|
162
163
|
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
3
test
CHANGED
@@ -156,7 +156,7 @@
|
|
156
156
|
上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
|
157
157
|
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
158
158
|
|
159
|
-
②で認証が必要になる場面で ①を呼び出して認証処理を肩代わりさせます。
|
159
|
+
②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
|
160
160
|
この過程でアクセストークンを ①の中に保管しておきます。
|
161
161
|
|
162
162
|
実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
|
2
test
CHANGED
@@ -124,7 +124,7 @@
|
|
124
124
|
|
125
125
|
② copy.gs
|
126
126
|
```js
|
127
|
-
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; //
|
127
|
+
const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
|
128
128
|
|
129
129
|
/**
|
130
130
|
* 認証用ダイアログ(html)表示
|
1
test
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
+ 逆に、コピー元のデプロイURLが変わってしまった場合は、コピー先ファイルに記載されているDEPLOY_URLを全部そのURLに修正しなければなりません。
|
6
6
|
|
7
|
-
+ アクセストークンを使うときは、その都度、getToken() を呼び出してください。
|
7
|
+
+ **アクセストークンを使うときは、その都度、getToken() を呼び出してください**。
|
8
8
|
|
9
9
|
+ セラーセントラルのAPI登録画面でのリダイレクトURIは、コピー元のcallbackから変更する必要はありません。
|
10
10
|
|
@@ -89,7 +89,7 @@
|
|
89
89
|
-----
|
90
90
|
# 説明
|
91
91
|
|
92
|
-
上記は、実質的に下記の2つのコードを合
|
92
|
+
上記は、実質的には下記の2つのコードを合体したものになります。
|
93
93
|
① original.gs
|
94
94
|
```js
|
95
95
|
AUTH_ENDPOINT = 'https://XXX';
|
@@ -154,7 +154,7 @@
|
|
154
154
|
```
|
155
155
|
|
156
156
|
上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
|
157
|
-
(
|
157
|
+
(冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
|
158
158
|
|
159
159
|
②で認証が必要になる場面で ①を呼び出して認証処理を肩代わりさせます。
|
160
160
|
この過程でアクセストークンを ①の中に保管しておきます。
|