バック：SpringBoot  フロント:Next.js　メール認証付きユーザー登録機能を実装

# 概要
バックエンド：SpringBoot RestApi 
フロントエンド:Next.js TypeScript
でBtoC向けECショップのクローンサイトを作ってます。

今回はログイン機能を実装します。

下の記事の続きですね。
[SpringBoot Rest-Apiメール認証付きユーザー登録機能の実装](https://qiita.com/RYA234/items/ecf37fdc2e080b1127f8)
前回はPostmanを使って挙動を確認しましたが、今回はフロントエンド側でページを作成　API処理を実行してユーザー登録できるようにします。

# ユースケース    
入力したメールアドレスが本当に所有者なのか確認するため、メールアドレス認証を行います。

１．ユーザーがEmailとPasswordを入力して登録ボタンを押す。
２．システムがデータベースにユーザーを”仮登録”の状態で登録して、認証するためにEmailを送信する。
３．ユーザーが認証メール中のリンクを押すと、登録完了される。



# 開発環境
OS:windows10

バックエンド側：
IDE:IntelliJ Community
spring-boot-starter-parent 2.75
java　：　11

データベース
mysql:8.0.29
クライアントソフト: MySQL Workbench

フロントエンド：
IDE:VScode

├── @types/node@18.11.15
├── @types/react-dom@18.0.9
├── @types/react@18.0.26
├── axios@1.2.1
├── eslint-config-next@13.0.6
├── eslint@8.29.0
├── next-auth@4.18.7
├── next@13.0.6
├── react-bootstrap@2.7.0
├── react-dom@18.2.0
├── react@18.2.0
├── styled-components@5.3.6
├── styled-jsx@5.1.1
└── typescript@4.9.4


# 実装

## 作成したファイル一覧
バックエンド
以下リンク参照
[SpringBoot Rest-Apiメール認証付きユーザー登録機能の実装](https://qiita.com/RYA234/items/ecf37fdc2e080b1127f8)


フロントエンド
主に作ったファイルはページ機能があるファイルです。
Next.jsの機能（routing DynamicRouting）を活用しています。
Reactは初回実行時するために、UseEffect使ったぐらいですね。

ファイル名|説明
---|---
customerService.ts| api処理が入っている　ライブラリはaxiosを利用
pages/regsiter.tsx|ユーザー情報を入力する時のページ
pages/registerComplete.tsx|register.tsxでユーザー登録が成功した時に遷移するページ
pages/verify/[code].tsx|メールのリンク先　URLに認証コードの値が入っている。ページを開くと初回実行時、ユーザーを有効化するApiを実行する　next.jsのdynamicRouting機能を使ってます。



## コード（長いので先に作成したファイル一覧をご覧ください）

### customerService.ts
```diff_tsx:customerService.ts
import axios from 'axios';
import { URLSearchParams } from 'url';
import { Customer } from '../types/customer';
import { response } from 'msw';

export const register= async (inputEmail:string,inputPassword:string) =>{
	return await axios.post(`http://127.0.0.1:5000/api/auth/signup`,
	{
		'email':inputEmail,
		'password':inputPassword
},

)
.then((response)=>{
	return response;
})
.catch((error)=>{
	return error;
})}

export const verify= async (verifyCode:string) =>{
	return await axios.put(`http://127.0.0.1:5000/api/auth/verify`,
	{
		'verifyCode':verifyCode
},
{ headers : {
	'Request-Method' : 'PUT',
	'Content-Type': 'application/json',
	'Access-Control-Allow-Origin': 'http://127.0.0.1:5000/*',
	'Access-Control-Allow-Headers': 'accept, accept-language, content-language, content-type',
	'Access-Control-Allow-Credentials': 'true'
}}
)
.then((response)=>{
	return response;
})
.catch((error)=>{
	return error;
})}






```

### register.tsx
```diff_tsx:register.tsx
import { useState } from 'react';
import { Customer } from '../types/customer';
import * as customerService from "../service/customerService";
import Router from 'next/router';

//　ユーザー登録ページ
// http://127.0.0.1:3000/register
export default function Register() {
	let inputEmail :string;
	let inputPassword :string;
	// ボタンを押したときに実行する関数
	const onRegisterClick = async (event: React.MouseEvent<HTMLButtonElement>) => {
		// todo エラーハンドリングの実装				
		const response = await customerService.register(inputEmail,inputPassword);
		Router.push('/registerComplete')
	}

	// Emailアドレスの入力値を変数に渡す
	const onChangeEmailHandler = (e: React.FormEvent<HTMLInputElement>) => {
		inputEmail=e.currentTarget.value;
	}
	// パスワードの入力値を変数に渡す
	const onChangePasswordHandler = (e: React.FormEvent<HTMLInputElement>) => {
		inputPassword=e.currentTarget.value;
	}
	return(
	<div className="Layout">
			<div>ユーザー登録画面</div>
			入力したEメールに認証メールが送られます。
			<div>Emailアドレス</div>
			<input type="text" onChange={onChangeEmailHandler}></input>		
			<div>パスワード</div>
			<input type="password" onChange={onChangePasswordHandler}></input>
			<br/>
			<br/>
			<button onClick={onRegisterClick} >ユーザー登録</button>
		<style jsx>{`
				.Layout{
					text-align: center;
				}
			`}</style>

	</div>
	) 
  }


```

### registerComplete.tsx
```diff_tsx:registerComplete.tsx
// ユーザー登録が完了したときに表示するページ
export default function registerComplete(){
return(
	<div>
		仮登録が完了しました。
		認証メールを送りましたので確認お願いします。
	</div>
)

}
```

### verify/[code].tsx
```diff_tsx:verify/[code].tsx
import { useRouter } from "next/router";
import {useEffect} from 'react';
import * as customerService from "../../service/customerService";

// 認証完了ページ
export default function Verify(){
	// URLのペラメーターverify/〇〇の〇〇部分を変数に渡している
	const {code} = useRouter().query;
	// 初回実行時に実行する
	 useEffect(()=>{
			verify();},[]);
	// 認証コードを送信する関数
	const verify = async()=> {
		const response = await customerService.verify(code as string);
	}

	return (
		<div>
			認証が完了しました。
			認証コード
			<div>{code}</div>
		</div>
	)
}
```



# 実装後の検証

gifアニメは左側ブラウザでviewの確認、右側MySQL workbenchでDBを確認しています。
## Emailとパスワードを入力して登録ボタンを押すまで
以下情報を入力
捨てメアドサイトで作った適当なアドレスです。
データベースに新しいユーザーが作成されていることを確認できます。
![front-register.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/0c99aaea-2ac5-d3b8-64e9-03ca076e51ce.gif)


## 送られてきたメールのリンクをクリックして認証を完了する
メールのリンクを開くと、仮登録ユーザーのパラメーターが変化し認証が完了します。
enabled=true
virification_code=null

![front-completed.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/3b8f8127-f729-86cd-3f63-d334abd832bf.gif)




# 課題
例外処理が未実装なので、追加の必要あり
１．バリデーション
２．Eメールアドレスを送信できなかった場合
３．既に認証が完了してるのにリンクを開いた場合
４．ユーザー登録ボタン押したときの待ちが時間が気になった。（本当に動作してるのかわからない）


# 参考