ODC版のUltimate PDFを確認(2)Tokenによるセキュリティ

基本的な利用手順を確認した、[ODC版のUltimate PDFを確認(1)](https://qiita.com/jyunji_watanabe/items/b898fbaf5e9bdd54327d)の続き。

# 環境情報
ODC Studio(Version 1.3.18)
Ultimate PDF (Version 1.1.5)
UltimatePDF_ExternalLogic (Version 0.1.5)
Template_UltimatePDF (Version 0.1.2)

# 概要
現状のUltimate PDFを利用するには、PDFに変換するScreenのAuthorizationをEveryoneにしないといけない。
このままではセキュリティの問題があるため、[GitHubのプロジェクトページ > Advance PDF Generation](https://github.com/OutSystems/UltimatePDF-ExternalLogic?tab=readme-ov-file#advance-pdf-generation)の手順に従い、実装手順を確認する。
ポイントは、
- ①PDF化する画面と、②PDF化する処理を起動する画面を分離する
- ②の画面では、ボタンクリック等によって処理を起動するが、セキュリティ検証用のTokenを生成してEntityに保存しておき、さらにTokenを①の画面をPDF化する際にパラメータに渡す
- ①PDF化する画面はAuthorization=Everyoneでセキュリティ無しに設定する。GitHubドキュメントに記述された方法では、OnInitializeでTokenの検証を行い、存在が確認できなければエラーにする

ただし、OnInitializeでTokenの検証を行うと、クライアントサイドで処理をバイパスされてしまう懸念がある。そこで、セキュアな情報は全てScreenのData Actionを介して取得し、さらにTokenの検証はData Actionの先頭で行うこととする

# App作成
Token生成・検証・保存、REST APIなど必要な要素を含むテンプレートがあるので、それをもとにAppを作成する。

Template_UltimatePDFをインストールし、App作成時にテンプレートとして、「Ultimate PDF」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/b2452b6c-71bb-2ac6-418d-751e6cae79e5.png)

# ②PDF化する処理を起動する画面
## UI（処理を起動するButton）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/068cc97a-e695-85d2-386b-3ea4cd02f162.png)
配置されたButtonをクリックすると、次のActionを呼び出して、①の画面をPDF化し、ダウンロードさせる。

## ロジック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/77d8d974-e75c-c247-df64-e70134c8df63.png)

処理のポイント
### CurrEnvironment Action (Ultimate PDF)
ブラウザのロケール・タイムゾーンなどを返す。
PrintToPDF_Advanced ActionのInput Parameter Environmentに、このActionのOutput Parameterを渡す。

### GeneratePDFToken Action (Template_UltimatePDF)とCommitTransaction
GeneratePDFTokenは、GUIDを生成し、App内のGeneratePDF Entityに保存しておく。
Print内では、
- Server Action内でGUIDの保存
- そのGUIDを使った①画面のPDF化
が一連の処理で行われる。つまり前者で保存したレコードは校舎の段階ではコミットされていない。それでいて、後者の処理は別のトランザクション内で発生する。この場合は、明示的に(System)のCommitTransaction Actionを呼ぶ必要がある。

これは、PrintToPDF_Advanced Actionが内部でExternal LogicのActionを呼んでおり、別トランザクションとなることによる。

### PrintToPDF_Advanced Action
（見る限りPrintToPDFを使っても良さそうだが、GitHubのドキュメントに従ってPrintToPDF_Advancedを使っておく）

以下がActionに渡すパラメータ。注意点として、URLはフルパスにする必要がある。これはExternal LogicがODCの外部で動作するため（Ultimate PDFは、指定したURLをPDF化するときに、External Logic内でブラウザを起動してURLを開き、その印刷機能を使ってPDF化する）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e7b24b6c-13ca-576e-7a0c-763b1df85501.png)

URLの編集例（AdvancedPDF1は、①のScreen名。TokenをInput Parameterに渡している点に注意）

``` 
"https://" + Request_GetDomain() + GetOwnerURLPath() + "AdvancedPDF1?Token=" + GeneratePDFToken.Token
```

# ①PDF化する画面
[ODC版のUltimate PDFを確認(1)](https://qiita.com/jyunji_watanabe/items/b898fbaf5e9bdd54327d)で使った画面を流用する。

対象のScreenをコピーし、配置してあるHideOnPrint Blockとその中身を削除する。
PDF出力を要求する部分を別の画面に移動するため、この画面には必要ないので。

## Data ActionでToken検証とセキュアな情報の取得を行う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/215652ed-c0dd-f1af-afd5-2bf277f9ff0c.png)

IsPDFTokeValid ActionはTemplateに含まれている、Tokenの検証用Action。
TokenでGeneratePDF Entityを検索し、存在が確認でき、かつIsAcrtive=TrueのときにのみPDF出力を許可することでセキュリティを確保する。

同じくTemplateに含まれるExpireToken ActionでTokenに対応するレコードのIsActiveをFalseにする。こうすることで、Tokenが有効な時間はごく短くなり、かつ1回のみしか利用できなくなる。

また、この構成の場合、OnInitializeでTokenを確認しないことから、Screenに固定で記述されている内容は権限がないユーザーも（URLを知っていれば）確認できる。
よって、セキュアな情報はToken検証後に実行されるData Actionから返すことにする。