Webアプリを作成して公開したい #4

続きです。Quitaの記事の編集にも少しづつ慣れてきました。

今回はアプリからDB接続をトライしていきます。
せっかくなのでSpring Securityを使用してログイン機能を実装していこうと思います。

セキュリティに関しては色々考慮する必要があるかと思います。
参考になった記事を備忘までに置いておきます。

・[新人の作ったWebアプリが穴だらけ!?　ログイン画面に潜むセキュリティの”あるある”ワナ](https://www.itmedia.co.jp/news/articles/2308/09/news091_2.html)
・[Spring Securityを使ったWebアプリケーションの基本①　〜ログイン機能の実装〜](https://qiita.com/homes31285/items/aa21f1d6c15b61ab811a)
・[ログイン機能とは｜仕組みや必要性、実装時の手順について](https://www.spiral-platform.co.jp/article/member/446/)
・[WEBアプリのログイン機構のセキュリティチェック観点](https://qiita.com/gakuri/items/a0057d4e56de5de35d8d)

 まとめると以下（初心者ステップ）
・パスワードの暗号化
・ログイン画面のパスワードのマスキング
・ログインエラーは必ずしも理由が明確にわかればよいわけではない
・SQLインジェクションへの考慮

この辺りは意識していきたいなと思います。
二段階認証とかもやってみたいですが
その辺りのセキュリティ対策は追々とします。

Spring Securityとは、は以下で分かりやすく説明してくれていました。

https://qiita.com/suger4/items/39b37af3705f2d0271c7

アプリケーション自体は作成済みなので以下の流れで進めていきます
１．DBテーブルの用意
２．Spring Security依存関係の追加
３．ログイン画面の実装
４．デプロイ

１．DBテーブルの用意
--
Spring Securityでは「パスワード」はハッシュ化して保存せよ、と推奨されているのでパスワードのカラムは必須です。
パスワードが紐づくキーとして「ユーザID」を設定します。
後々ロールなども考えていきたいのでカラムとして保持しますがここは一旦適当な値を入れて置き、後ほどロール定義用のテーブルを設定することとします。

命名規則についてはプロジェクトごとの定義があると思いますが
今回はこちらを参考にしました。

https://qiita.com/genzouw/items/35022fa96c120e67c637

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/60ebf7ba-7c11-a031-e5c5-0c9ce5910847.png)

```
CREATE TABLE users( 
    user_id VARCHAR (255) NOT NULL COMMENT 'ユーザID'
    , role_code INT NOT NULL COMMENT '権限コード'
    , last_name VARCHAR (255) NOT NULL COMMENT '姓'
    , first_name VARCHAR (255) NOT NULL COMMENT '名'
    , last_name_kana VARCHAR (255) COMMENT '姓（カナ）'
    , first_name_kana VARCHAR (255)   COMMENT '名（カナ）'
    , password  VARCHAR (255) NOT NULL COMMENT 'パスワード'
    , email  VARCHAR (255) COMMENT 'メールアドレス'
    , created_at DATETIME NOT NULL COMMENT '初期登録日時'
    , created_user VARCHAR (255) NOT NULL COMMENT '初期登録者'
    , update_at DATETIME NOT NULL COMMENT '最終更新日時'
    , update_user VARCHAR (255) NOT NULL COMMENT '最終更新者'
    , valid_flag BOOLEAN NOT NULL COMMENT '有効フラグ'
    , version INT NOT NULL COMMENT 'バージョン'
    , PRIMARY KEY (user_id)
    , UNIQUE KEY (user_id)
) DEFAULT CHARSET = utf8;
```
上記を実行してテーブルの登録が完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/36404777-f08d-f4e3-c98d-65bdba32a8a3.png)

データはひとまず入れずに、次に進みます。

２．Spring Security依存関係の追加
--

pom.xmlに記述のある以下をダブルクリックすると
依存関係が追加できるウィンドウが出てきました。便利。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/e6f20a2b-fd0a-381f-5c6c-a6a8a1dda7aa.png)

「次へ」で追加を完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/ce36a2fb-90ef-7124-63bf-38a8a951fb3d.png)

３．ログイン画面の実装
--
これは以下を参考にして実装しました。

https://qiita.com/EasyCoder/items/3a717db1761ddd9d3ae0

DB接続値は環境変数を使用して環境ごとの設定値の変動を許容します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/800688af-769d-5b8e-a291-35564c87e589.png)

参考

https://qiita.com/turn-take/items/75975d15625c3a750000

他にもいろいろハマりかけましたが、多いので記事の最後にまとめています。

４．デプロイ
--
デプロイ前に本番環境でDBを作成し、環境変数を設定します。

色々躓きまして、大変な思いをしました。
railwayの開設をしているサイトが少ないのでどなたかの助けになればと思います。

まず、railway上で作成したアプリケーションの階層にある
「＋Create」からMySQLのDBを作成しました。
サイト上でテーブルを作成しましたが、型の指定にVARCHARがないので
コマンドプロンプトでrailwayで作成したDBに接続して
ローカルで作成したときに使用したCREATE TABLEコマンドでテーブル作成をしました。

接続コマンドはrailway上で確認できます。
以下の「Connect」から「Public Network」タブを参照すると
「Raw mysql command」がありますのでそちらを使用してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/7edf154f-8c2b-7eb8-7dbc-2115a5098012.png)

コマンドプロンプトから接続してテーブルを作成したら環境変数の設定です。
application.propertiesには以下のように定義しています。
```
# データベースに接続するためのURL
spring.datasource.url=${DATASOURCE_URL}

# データベースに接続するためのユーザー名
spring.datasource.username=${DATASOURCE_USERNAME}

# データベースに接続するためのパスワードを設定
spring.datasource.password=${DATASOURCE_PASSWORD}
```
なので本番環境となるrailwayでも同じ名前の環境変数で値を設定してあげる必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/1354fadd-c1d5-1646-2918-a304fa03d633.png)

ホスト名とポートは不要でしたが一応設定しました。
railway公式ではrailway内のサービスであれば
固有のバインド変数を使用して変数の参照ができるとのことでしたが
うまくできなかったのでべた書きで設定しました。

値はDBの持っている変数に記載がある内容で設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/26d965a2-e76f-badc-ab3a-cd9a29cd1666.png)

ここでハマったのがURLです。
上記の画像にある「MYSQL_URL」の値を
アプリから参照する「DATASOURCE_URL」として設定しましたが
デプロイ後に以下のエラーが発生しました。

```
HikariPool-1 - Starting...
No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException

ERROR UsernamePasswordAuthenticationFilter : An internal error occurred while trying to authenticate the user.

org.springframework.security.authentication.InternalAuthenticationServiceException: Driver com.mysql.cj.jdbc.Driver claims to not accept jdbcUrl, mysql://root:＊＊＊＊＊@autorack.proxy.rlwy.net:＊＊＊＊＊/＊＊＊＊＊
```
__mysql://root:＊＊＊＊＊@autorack.proxy.rlwy.net:＊＊＊＊＊/＊＊＊＊＊__

（＊＊＊＊＊はマスキングですのでログ上は環境変数に設定した通り出力されました）
上記が「DATASOURCE_URL」として設定したURLですが
接続できんよ、と言われています。
大体このエラーは接続情報の設定誤りが原因ですが色々確認しても原因がわからずハマりました。

結論として、URLの頭に「jdbc:」がないことが原因でした。

色々な記事をみて「mysql:」を「mysql2:」にしたり
変数の値を変えてみたりしましたが単純なことでした。

デプロイしてアプリに接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/223c330e-4bd1-2cda-3c8d-c4273b779a6c.png)

ユーザマスタは空のはずなので「新規登録」からアカウントを発行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/85e38de0-c0f5-8642-6968-cad6908c2efb.png)

ログインできることを確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/9d9df44b-7e7a-b2ba-ba11-831bd9ed8369.png)

これで一旦環境は整いました。
次回はアプリ機能を充実させていきます。

実装時にハマりかけた箇所のTips
--
★javaxがなくエラーとなる
先のリンクを参考にして実装を進める中でjavax指定のライブラリが見つからないエラーがありまして、調べたところSpringBootのバージョンの問題で別のものに置き換わっていたことがわかりました。

https://kazuki-room.com/post-6362/

★DB接続がタイムアウトする
解決まで結構時間がかかりました。
出ていたエラーは以下。

```
HikariPool-7 - Starting...
SQL Error: 0, SQLState: 08S01
Communications link failure
～中略～
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.] [n/a]
```

https://www.ibm.com/docs/ja/imdm/11.6?topic=sswsr9-11-6-0-com-ibm-pim-trb-doc-pim-ref-issue87-html

https://qiita.com/k_hoso/items/9969313c0d6815d8f381

https://qiita.com/yukiyoshimura/items/a2c2c625bc1837d0f2ae

https://qiita.com/t0k0sh1/items/24e6cbf68a1b513f4e4a

最終的にはapplication.propertiesに以下の記載を追加して解決しました。

```
# タイムアウト
spring.datasource.hikari.connection-timeout=600
```

★antMatchersが使用できない
SpringSecurityのセキュリティ内容を記載するSecurityConfig.javaのコーディングです。
antMatchersが使えませんでしたがバージョンの問題でお作法が変わっていました。

https://qiita.com/suke_masa/items/908805dd45df08ba28d8


★cssが適用されない
かなり時間を要しました。
SpringSecurityのセキュリティによってアクセスが制御されてしまっているため
css/style.cssにアクセスできず以下のエラーが画面側で発生していました。

```
Refused to apply style from 'http://localhost:8080/login' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
```
色々なところに記載があるようにSecurityConfig.javaにcssとimgだけ対象外とするように記載すると解決するとありましたが、うまくいかなかったため
最終的にcssをHTMLに直書きする形にしました。
imgを使用するときに鬼門になるかもしれませんが一旦保留とします。
解決策をご存じの方はご教授ください...。

https://qiita.com/maro-maro/items/c733af89ce7281062854