【make it easy】efwのwebアプリのログイン制御＆権限制御

# はじまり
webアプリに、ログイン有無とユーザ権限で画面操作可否を制御するのはよくあります。社内のwebアプリの場合、ユーザはよい人ばかりですから、制御の厳密さにあまり気にしなくてよいですが、社外向けあるいはインタネット向けの場合、気を付けたほうがいいです。権限なしのweb画面をURL欄で直接打ち込むこと、または権限なしのイベントをデベロッパーツールで直接呼び出すことなど、軽いハッキングのリスクはインタネットにいつも存在しています。

efwは、プロパティ設定の方式で、上記リスクを防ぐこと実現しております。今回の記事をこれを紹介させていただきます。

# スケルトンサンプル
スケルトンサンプルは、ログイン画面・メニュー画面・マスタ管理画面で構成します。マスタ管理画面は、ログインユーザの権限により操作可否を制御したいです。

## 画面イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/8c4522a5-6725-3670-8b16-3235f4986dc2.png)

## フォルダ構成
権限制御に関わる要素をリストします。制限不要の画像・CSSは除外しています。
```
skeletonSample
│  error.jsp　　　　　　　　　エラー画面
│  head.jsp　　　　　　　　　 ヘッダ部品
│  headbeforelogining.jsp　　ヘッダ部品（ログイン前画面向け）
│  headwithoutmenu.jsp　　　 ヘッダ部品（メニューリンク無し画面向け）
│  LG01.jsp　　　　　　　　　 ログイン画面
│  LG02.jsp　　　　　　　　　 メニュー画面
│  LG03.jsp　　　　　　　　　 パスワード忘れ画面
│  LG04.jsp　　　　　　　　　 パスワード変更画面
│  MST01.jsp　　　　　　　　  ユーザマスタ画面
│  MST01_inputdialog.jsp　　 ユーザ登録サブ画面（部品取り扱い）
│  MST01_uploaddialog.jsp　　アップロードサブ画面（部品取り扱い）
│  paging.jsp　　　　　　　　 ページング部品
│  
└─WEB-INF
    │  
    ├─classes
    │      efw.properties
    │      
    └─efw
        └─event
                global.js
                head_logout.js　　ログアウトイベント
                LG01_clear.js
                LG01_cookie.js
                LG01_submit.js
                LG02_goto.js
                LG03_chgPwd.js
                LG03_init.js
                LG04_sndPwd.js
                MST01_add.js
                MST01_clear.js
                MST01_delete.js
                MST01_download.js
                MST01_edit.js
                MST01_init.js
                MST01_inputdialog_init.js
                MST01_inputdialog_save.js
                MST01_search.js
                MST01_upload.js
                MST01_uploaddialog_save.js
```
# ログイン制御
## 目標説明
- 以下の画面および関連イベントはログインチェックが不要です。つまり未ログインの状態で操作しても大丈夫です。
・ログイン画面
・パスワード忘れ画面
・パスワード変更画面
・エラー画面
- 以下の画面および関連イベントはログインチェックが必要です。つまり未ログインの状態で操作したらエラーです。
・メニュー画面
・ユーザマスタ画面
- 部品またはサブ画面は、単独で呼び出せないようにしたいです。
- ログアウトイベントは、未ログインの状態でも呼び出せる必要です。
例えばメニュー画面が長い時間開いたまま放って置いたら、タイムアウトになります。この状態でログアウト操作して、「ログインください」アラートを出すと違和感があります。

## プロパティ設定
efw.propertiesファイルに以下のように設定して上記要望を対応します。
```properties
efw.login.check = true
efw.login.key = USER_ID
efw.login.url = LG01.jsp
efw.outoflogin.url.pattern =[/](LG01|LG03|LG04).jsp
efw.outoflogin.eventid.pattern = LG01|LG03|LG04|head_logout
```
設定の意味を翻訳します。
・ログイン制御を有効にします。
・ログイン制御に使うセッション項目はUSER_IDです。
・ログイン画面はLG01.jspです。
・ログイン制御不要の画面は、LG01.jsp、LG03.jsp、LG04.jspです。
・LG01、LG03、LG04、head_logoutの文字を含むイベントはログイン制御不要です。

部品とサブ画面の場合、< efw:client >タグを含まないですから、無理やり画面から呼び出しても、イベントが実行されないから、設定に含まなくてもよいです。

## 動作説明
- 上記設定により、未ログイン状態（タイムアウト状態）で、ログインチェック対象のメニュー画面などを操作する際、ログイン画面に自動的に遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/34a3bd98-9685-180f-f770-c68e05407288.png)

- ログインチェック対象のイベントは、未ログイン状態（タイムアウト状態）で実行される場合、以下のエラーを出してログイン画面へ自動的に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ef72bca0-6d1a-b9d5-5e42-e6a684a05bf1.png)

- デベロッパーツールで軽いハッキングも同じくチェックされます。
以下のエビデンスは、未ログイン状態でログイン画面からユーザマスタ画面のイベントを呼び出すお試しです。イベント引数は基本的に画面とバインドしているから呼び出したらエラーが発生しますが、カスタマイズ引数の悪用でまたは引数なしの場合は呼び出せます。このとき、ログインチェック機能がガードしてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/1ce24bfe-40c8-e531-4f31-7f747c30c9d7.png)
 

# 権限制御
## 目標説明
ログインユーザはさらに２種類に分けて、管理者と一般ユーザにします。
- 管理者
すべての画面と関連イベントをアクセスできます。
- 一般ユーザ
ユーザマスタの画面と関連イベントをアクセスできません。

## プロパティ設定
```properties
efw.auth.check = true
efw.auth.key = USER_ID
efw.system.error.url = error.jsp
efw.auth.cases = admin,user
admin.auth.pattern = ^admin.*$
admin.url.pattern = [/](LG02|MST01).jsp
admin.eventid.pattern = LG02|MST01
user.auth.pattern = ^((?!admin).)*$
user.url.pattern = [/](LG02).jsp
user.eventid.pattern = LG02
```
設定の意味を翻訳します。
・権限制御を有効します。
・権限制御に使うセッション項目はUSER_IDです。
・権限制御エラー時、システム画面のerror.jspに遷移します。
・ロールは２種類、管理者と一般ユーザです。
・「admin##」のUSER_IDなら、管理者ロールに該当します。
・管理者は、LG02.jspとMST01.jspの画面をアクセスできます。
・管理者は、LG02とMST01の文字を含むイベントをアクセスできます。
・「admin##」のUSER_IDではない場合、一般ユーザに該当します。
・一般ユーザは、LG02.jsp画面をアクセスできます。
・一般ユーザは、LG02の文字を含むイベントをアクセスできます。

メニュー画面の「ユーザ管理」ボタンは、一般ユーザが見えないようにしたらベストですが、ロールを判断してボタンの表示可否を制御するプログラムが必要です。プロパティファイル設定ではなく、メニュー画面のプログラムでやってください。

LG01.jsp、LG03.jsp、LG04.jsp、error.jspと関連イベントは、ログイン不要ですから、権限制御も対象外です。つまり、だれでもみてよい画面です。

## 動作説明
- 一般ユーザは、URL欄で閲覧禁止のURLを接続しようとする場合、システムエラー画面に遷移されます。且つ、理由を説明しません。※ハッカーに親切不要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/d1675a72-2b05-e4a5-c461-57a56b69a348.png)

- 操作禁止のイベントを、デベロッパーツールから実行する場合、予想外エラーのメッセージを表示します。エラーメッセージを閉じると、システムエラー画面に遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/9cd9519b-e3c0-6389-1f65-44232f249995.png)

システムにとって、操作禁止だったらボタンが非活性になるのは一般的にです。つまり通常操作により、禁止される画面とイベントに行かないはずです。そして、権限制御のエラーは、ハッキングの理由しかありません。システムエラーを出すのは正しいです。

# 環境
スケールトンサンプルは、DB、メール、POIを利用しています。
環境構築に関わる情報は、以前に記事を読んでください。

https://qiita.com/changkejun/items/b273b3ae64c76e5b016a

https://qiita.com/changkejun/items/c237ddbc69c9c4cb3319

https://qiita.com/changkejun/items/dea128563b608b7dcb43


サンプルフォルダ直下においているskeletonSample.backupファイルは、postgresのバックアップファイルです。リストアすれば使えます。ほかのデータベースを利用したい場合、以下のSQLを参考してテーブルを作成してください。
```SQL
CREATE TABLE "ユーザマスタ"
(
  "ユーザID" character varying(10) NOT NULL, -- ユーザID
  "パスワード" character varying(10), -- パスワード
  "ユーザ名" character varying(20), -- ユーザ名
  "メール" character varying(50), -- メール
  "コメント" character varying(200), -- コメント
  "初期化フラグ" integer, -- 初期化フラグ	 1：初期パスワードの場合　...
  "ロックフラグ" integer, -- ロックフラグ
  "パスワード更新日" date, -- パスワード更新日
  "作成日時" date, -- 作成日時
  "作成者" character varying(10), -- 作成者
  "更新日時" date, -- 更新日時
  "更新者" character varying(10), -- 更新者
  CONSTRAINT "ユーザマスタ_PKC" PRIMARY KEY ("ユーザID")
);
```

今回のサンプルは、ここからダウンロードできます。

https://github.com/efwGrp/qittaSamples