概要
プログラムの勉強を始めて5か月ほどの開業医です。
今回Auth0を使ったユーザー認証を勉強したので、花粉症の重症度が分かるWEBアプリに実装してみました。
花粉症(アレルギー性鼻炎)の重症度はくしゃみ・鼻水・鼻づまりの程度で判定できるので、その診断アルゴリズムをプログラミングしています。
実装
Googleアカウントを使ったユーザー認証機能。
ボタンを選択すると鼻アレルギーの重症度が分かるWEBアプリ。
完成動画
— 病気のセルフチェック (@Selfcheckhealt1) December 9, 2019
完成画像
作成方法
※完成動画と画像ではGoogleアカウントだけでなく、LINEアカウントでのユーザー認証機能も実装していますが、今回の記事ではLINEアカウント認証の実装法の説明は省いております。
1. Auth0のアカウント作成・サインイン
こちらから行ってください。
Auth0ホームページ
ログインしダッシューボードのCREATE APPLICATIONを押します。
今回は名前はMy Selfcheck AppでSingle Page Web Applicationsを選択してCREATEを押します。
DOWNLOAD SAMPLEをクリックします。
1.2. 3. の設定を、Application Settingsを行います。
SAVE CHANGED で設定反映を忘れないようにします。
3.ダウンロードと解凍
ダウンロードを押します。
ZIPファイルがダウンロードされるので、自分のプロジェクトフォルダに保存します。
ZIPファイルを解凍します。
4. 移動
フォルダを移動します。
cd vanillajs-01-login/01-login
npm start
このコマンドを実行します
http://localhost:3000/ が起動します。
5. プログラム作成
サンプルの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アプリを作成するとができました。
ユーザー認証があるだけでちゃんとしたアプリ感が出ると思います。
今後はユーザー情報を利用した機能を追加していきたいと思いました。