花粉症の重症度が分かるWEBアプリの作成～Auth0でユーザー認証～

##概要
プログラムの勉強を始めて5か月ほどの開業医です。

今回Auth0を使ったユーザー認証を勉強したので、花粉症の重症度が分かるWEBアプリに実装してみました。

花粉症（アレルギー性鼻炎）の重症度はくしゃみ・鼻水・鼻づまりの程度で判定できるので、その診断アルゴリズムをプログラミングしています。

##実装
Googleアカウントを使ったユーザー認証機能。
ボタンを選択すると鼻アレルギーの重症度が分かるWEBアプリ。

##完成動画

<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/uwNOQt9sC4">https://t.co/uwNOQt9sC4</a></p>&mdash; 病気のセルフチェック (@Selfcheckhealt1) <a href="https://twitter.com/Selfcheckhealt1/status/1204188879110037505?ref_src=twsrc%5Etfw">December 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

##完成画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/509cc07b-1aed-ec7e-8968-5ffbbd8d839e.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/e2ba20a5-76aa-5255-1738-5440b6ff24e7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/bd7f40bb-8c81-7b9a-1af6-2d031d73c147.png)




##作成方法
※完成動画と画像ではGoogleアカウントだけでなく、LINEアカウントでのユーザー認証機能も実装していますが、今回の記事ではLINEアカウント認証の実装法の説明は省いております。

**1. Auth0のアカウント作成・サインイン**
こちらから行ってください。
[Auth0ホームページ](https://auth0.com/jp/)

**2. 基礎プロジェクトの作成**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/a5309533-eac0-9659-6ae3-8b6d6425a8ab.png)

ログインしダッシューボードのCREATE APPLICATIONを押します。

今回は名前はMy Selfcheck AppでSingle Page Web Applicationsを選択してCREATEを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/5eda1641-01be-1bdb-e07c-64b3ddfb2307.png)

今回はJavaScriptを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/494a0ea6-d258-53ce-e55b-c131bb49e747.png)

DOWNLOAD　SAMPLEをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/f8b81f24-1d72-2b73-23f1-8ba8c6d788c1.png)

1.2. 3. の設定を、Application Settingsを行います。

SAVE CHANGED で設定反映を忘れないようにします。

**3.ダウンロードと解凍**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/67eba73f-5b9e-54d1-25b6-3bbc6c0660ba.png)

ダウンロードを押します。

ZIPファイルがダウンロードされるので、自分のプロジェクトフォルダに保存します。
ZIPファイルを解凍します。


**4. 移動**
フォルダを移動します。

```
cd vanillajs-01-login/01-login
```
```
npm start
```
このコマンドを実行します

http://localhost:3000/ が起動します。

**5. プログラム作成**

サンプルのHTMLを以下のように書き換えました。

```html
<!DOCTYPE html>
<html class="h-100">
  <head>
    <meta charset="UTF-8" />
    <title>SPA SDK Sample</title>
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    />
    <link rel="stylesheet" type="text/css" href="/css/auth0-theme.min.css" />
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
    <link
      rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/monokai-sublime.min.css"
    />
    <link
      rel="stylesheet"
      href="https://use.fontawesome.com/releases/v5.7.2/css/solid.css"
      integrity="sha384-r/k8YTFqmlOaqRkZuSiE9trsrDXkh07mRaoGBMoDcmA58OHILZPsk29i2BsFng1B"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      href="https://use.fontawesome.com/releases/v5.7.2/css/fontawesome.css"
      integrity="sha384-4aon80D8rXCGx9ayDt85LbyUHeMWd3UiBaWliBlJ53yzm9hqN21A+o1pqoyK04h+"
      crossorigin="anonymous"
    />

    <link
      rel="stylesheet"
      href="https://cdn.auth0.com/js/auth0-samples-theme/1.0/css/auth0-theme.min.css"
    />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  </head>

  <body class="h-100">
    <div id="app" class="h-100 d-flex flex-column">
      <div class="nav-container">
        <nav class="navbar navbar-expand-md navbar-light bg-light">
          <div class="container">
            <!-- <div class="navbar-brand logo"></div> -->
            <!-- ブランドロゴはこちら -->
            <img
              class="mb-3 app-logo"
              src="https://self-check.net/wp-content/uploads/2019/05/Logo-e1557133216298.png"
              alt="self-check logo"
              width="150"
            />
            <button
              class="navbar-toggler"
              type="button"
              data-toggle="collapse"
              data-target="#navbarNav"
              aria-controls="navbarNav"
              aria-expanded="false"
              aria-label="Toggle navigation"
            >
              <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                  <a href="/" class="nav-link route-link">Home</a>
                </li>
              </ul>
              <ul class="navbar-nav d-none d-md-block">
                <!-- Login button: show if NOT authenticated -->
                <li class="nav-item auth-invisible">
                  <button
                    id="qsLoginBtn"
                    onclick="login()"
                    class="btn btn-primary btn-margin auth-invisible hidden"
                  >
                    Log in
                  </button>
                </li>
                <!-- / Login button -->

                <!-- Fullsize dropdown: show if authenticated -->
                <li class="nav-item dropdown auth-visible hidden">
                  <a
                    class="nav-link dropdown-toggle"
                    href="#"
                    id="profileDropDown"
                    data-toggle="dropdown"
                  >
                    <!-- Profile image should be set to the profile picture from the id token -->
                    <img
                      alt="Profile picture"
                      class="nav-user-profile profile-image rounded-circle"
                      width="50"
                    />
                  </a>
                  <div class="dropdown-menu">
                    <!-- Show the user's full name from the id token here -->
                    <div class="dropdown-header nav-user-name user-name"></div>
                    <a
                      href="/profile"
                      class="dropdown-item dropdown-profile route-link"
                    >
                      <i class="fas fa-user mr-3"></i> Profile
                    </a>
                    <a
                      href="#"
                      class="dropdown-item"
                      id="qsLogoutBtn"
                      onclick="logout()"
                    >
                      <i class="fas fa-power-off mr-3"></i> Log out
                    </a>
                  </div>
                </li>
                <!-- /Fullsize dropdown -->
              </ul>

              <!-- Responsive login button: show if NOT authenticated -->
              <ul class="navbar-nav d-md-none auth-invisible">
                <button
                  class="btn btn-primary btn-block auth-invisible hidden"
                  id="qsLoginBtn"
                  onclick="login()"
                >
                  Log in
                </button>
              </ul>
              <!-- /Responsive login button -->

              <!-- Responsive profile dropdown: show if authenticated -->
              <ul
                class="navbar-nav d-md-none auth-visible hidden justify-content-between"
                style="min-height: 125px"
              >
                <li class="nav-item">
                  <span class="user-info">
                    <!-- Profile image should be set to the profile picture from the id token -->
                    <img
                      alt="Profile picture"
                      class="nav-user-profile d-inline-block profile-image rounded-circle mr-3"
                      width="50"
                    />
                    <!-- Show the user's full name from the id token here -->
                    <h6 class="d-inline-block nav-user-name user-name"></h6>
                  </span>
                </li>
                <li>
                  <i class="fas fa-user mr-3"></i>
                  <a href="/profile" class="route-link">Profile</a>
                </li>

                <li>
                  <i class="fas fa-power-off mr-3"></i>
                  <a href="#" id="qsLogoutBtn" onclick="logout()">Log out</a>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </div>

      <div id="main-content" class="container mt-5 flex-grow-1">
        <div id="content-home" class="page">
          <div class="text-center hero">
            <!-- ブランドロゴはこちら           -->
           <img
              class="mb-3 app-logo"
              src="https://self-check.net/wp-content/uploads/2019/05/Logo-e1557133216298.png"
              alt="self-check logo"
              width="300"
            />
           
            <div class="container">

              <!-- https://materializecss.com/buttons.html -->
　　
              <h4>こんにちは<font color=#00bfff class="user-name" ></font>さん！</h4>
              <p></p>
              <h5>くしゃみは1日平均何回ですか？</h5>        
              <form action="#">
                      <p>
                        <label>
                          <input class="with-gap" name="group1" type="radio" value="4" checked />
                          <span>21回以上</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap"name="group1" type="radio" value="3" />
                          <span>20～11回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group1" type="radio" value="2"  />
                          <span>10～6回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group1" type="radio" value="1"  />
                          <span>5～1回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group1" type="radio" value="0"  />
                          <span>0回</span>
                        </label>
                      </p>
                    </form>
              
              <h5>鼻をかむのは1日平均何回ですか？</h5>
              <form action="#">
                      <p>
                        <label>
                          <input class="with-gap" name="group2" type="radio" value="4" checked />
                          <span>22回以上</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap"name="group2" type="radio" value="3" />
                          <span>20～11回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group2" type="radio" value="2"  />
                          <span>10～6回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group2" type="radio" value="1"  />
                          <span>5～1回</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group2" type="radio" value="0"  />
                          <span>0回</span>
                        </label>
                      </p>
                    </form>
              
              <h5>鼻づまりはどの程度ですか？</h5>
              <form action="#">
                      <p>
                        <label>
                          <input class="with-gap" name="group3" type="radio" value="4" checked />
                          <span>1日中完全につまっている</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap"name="group3" type="radio" value="3" />
                          <span>鼻づまりが非常に強く、口呼吸が1日の内かなりの時間あり</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group3" type="radio" value="2"  />
                          <span>鼻閉が強く、口呼吸が1日のうち、ときどきあり</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group3" type="radio" value="1"  />
                          <span>口呼吸は全くないが鼻閉あり</span>
                        </label>
                      </p>
                      <p>
                        <label>
                          <input class="with-gap" name="group3" type="radio" value="0"  />
                          <span>鼻閉なし</span>
                        </label>
                      </p>
                    </form>
              <div id="evaluation"></div>
              
              <button type="button">鼻アレルギーの重症度を判定</button>    
              
          </div>

          <div class="next-steps">
            <h5 class="my-5 text-center">自分に合ったアレルギー薬を選びましょう</h5>

            <div class="row">
              <div class="col-md-5 mb-4">
                <h6 class="mb-3">
                  <a href="https://auth0.com/docs/connections">
                    <i class="fas fa-link"></i> 花粉飛散情報はこちら
                  </a>
                </h6>
                <!-- <p>
                  リンク先の説明文
                </p> -->
              </div>

              <div class="col-md"></div>

              <div class="col-md-5 mb-4">
                <h6 class="mb-3">
                  <a href="https://auth0.com/docs/multifactor-authentication">
                    <i class="fas fa-link"></i>アレルギーのお役立ち情報はこちら
                  </a>
                </h6>
                <p>
                  <!-- <p>
                  リンク先の説明文
                  </p> -->
                </p>
              </div>
            </div>

            <div class="row">
              <div class="col-md-5 mb-4">
                <h6 class="mb-3">
                  <a href="https://auth0.com/docs/anomaly-detection">
                    <i class="fas fa-link"></i>市販の医薬品はこちら
                  </a>
                </h6>
                <p>
                  <!-- <p>
                  リンク先の説明文
                  </p> -->
                </p>
              </div>

              <div class="col-md"></div>

              <div class="col-md-5 mb-4">
                <h6 class="mb-3">
                  <a href="https://auth0.com/docs/rules">
                    <i class="fas fa-link"></i> 花粉症カレンダーはこちら
                  </a>
                </h6>
                <p>
                  <!-- <p>
                  リンク先の説明文
                  </p> -->
                </p>
              </div>
            </div>
          </div>
        </div>

        <div class="page" id="content-profile">
          <div class="container">
            <div class="row align-items-center profile-header">
              <div class="col-md-2">
                <img
                  alt="User's profile picture"
                  class="rounded-circle img-fluid profile-image mb-3 mb-md-0"
                />
              </div>
              <div class="col-md">
                <h2 class="user-name"></h2>
                <p class="lead text-muted user-email"></p>
              </div>
            </div>

            <div class="row">
              <pre class="rounded">
                <code id="profile-data" class="json"></code></pre>
            </div>
          </div>
        </div>
      </div>

      <footer class="bg-light text-center p-5">
        <!-- ブランドロゴはこちら -->
        <!-- <div class="logo"></div> -->
        <img
              class="mb-3 app-logo"
              src="https://self-check.net/wp-content/uploads/2019/07/9ad0bd5a51dadd4d06039943c511517d.jpg"
              alt="self-check logo"
              width="150"
            />
        <p>
          ©  katsuyukidoi 2019
        </p>
        
        <!-- <p>
          //画像を入れるならこちら
          <a href="">画像説明</a>
        </p> -->
      </footer>
    </div>
    <script>
     alert("鼻アレルギーの重症度を判定しましょう！");
      let severity="";
      
      $("#judgment").click(function() {
          score1 = $('input[name="group1"]:checked').val();
          score2 = $('input[name="group2"]:checked').val();
          score3 = $('input[name="group3"]:checked').val();

          if (score1=='4' || score2=='4' || score3=='4' ) {
              severity = "最重症";
          } else if (score1=='3' || score2=='3' || score3=='3'){
              severity = "重症";
          } else if (score1=='2' || score2=='2' || score3=='2'){
              severity = "中等症";
          } else if (score1=='1' || score2=='1' || score3=='1'){
              severity = "軽症";
          } else {
              severity = "無症状"
          }    

          $("#evaluation").html(`<h5>あなたの鼻アレルギーの重症度：${severity}</h5>`);
      });

    
    </script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
    <script src="js/auth0-theme.min.js"></script>
    <script src="https://cdn.auth0.com/js/auth0-spa-js/1.2/auth0-spa-js.production.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/highlight.min.js"></script>
    <script src="js/ui.js"></script>
    <script src="js/app.js"></script>
  </body>
</html>

```



##考察
Auth0はユーザー認証に必要な複雑な手順の多くを代わりにやってくれますので、今回数時間でユーザー認証機能が付いたWEBアプリを作成するとができました。
ユーザー認証があるだけでちゃんとしたアプリ感が出ると思います。
今後はユーザー情報を利用した機能を追加していきたいと思いました。