こんにちは、KOUKIです。Reactで画面開発を行なっています。
前回は、ユーザーの登録処理を実装しました。
今回は、ログイン処理を実装します。
尚、「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
前回
ログイン
以前、ログイン画面を実装しました。

EmailとPasswordをAPI側へ送信して、ログインできるようにしましょう。
データバインディング
Email/Passwordを打ち込んだ時に、情報を内部に保持する仕組みを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// pages/Login.tsx import { useState } from 'react' import '../Login.css' const Login = () => { // 1. ログイン情報 const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( <main className="form-signin"> <form> <h1 className="h3 mb-3 fw-normal">Please sign in</h1> <div className="form-floating"> <input type="email" className="form-control" id="floatingInput" placeholder="name@example.com" // 2. Emailをセット onChange={e => setEmail(e.target.value)} /> <label htmlFor="floatingInput">Email address</label> </div> <div className="form-floating"> <input type="password" className="form-control" id="floatingPassword" placeholder="Password" // 2. Passwordをセット onChange={e => setPassword(e.target.value)} /> <label htmlFor="floatingPassword">Password</label> </div> <button className="w-100 btn btn-lg btn-primary" type="submit">Sign in</button> </form> </main> ) } export default Login |
コメントをつけた場所が、変更箇所です。
1では、ステートフックを利用しています。
これを使うと、任意の情報をReactアプリ内に保持しておくことができるようになります。
2では、入力したデータを1で設定したStateに格納しています。
書き方としては、「[XXXX, setXXXX] = useState(デフォルト値)」であり、XXXXはなんでもいいです。格納したいデータに関連する名前をつけましょう。
BaseURLの設定
APIへの送信処理ですが、axiosを使っています。
このaxiosには、baseURLというプロパティを持っており、その名の通り、ベースとなるURLを設定することが可能です。
react-admin/src/index.tsxファイルに、BaseURLの設定を行いましょう。
1 2 3 4 5 6 7 8 9 |
// src/index.tsx ... import axios from 'axios' // BaseURL axios.defaults.baseURL = 'http://localhost:8000/api/admin/' ReactDOM.render(...); ... |
「http://localhost:8000/api/admin/」までのURLがベースになるので、上記のように設定しました。
前回作成したユーザー登録処理で設定したURLを以下のように変更します。
1 2 3 4 5 6 7 |
// pages/Register.tsx ... class Register extends Component { // registerUrl = 'http://localhost:8000/api/adminregister' registerUrl = 'register' } |
これならだいぶスッキリしますね。
Submit処理
ログイン情報をAPIへSubmitする処理を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// pages/Login.tsx import { SyntheticEvent, useState } from 'react' import '../Login.css' import axios from 'axios' import { Redirect } from 'react-router' const Login = () => { // ログイン情報 ... const loginUrl = 'login' const [redirect, setRedirect] = useState(false) const submit = async (e: SyntheticEvent) => { // formのデフォルトの挙動をキャンセル e.preventDefault() // ログイン情報を送信 await axios.post(loginUrl, { email: email, password: password // withCredentials // リクエストに Cookie を添えて送信する // API側ではCookieにTokenを保存している }, {withCredentials: true}) // リダイレクトフラグをTrue setRedirect(true) } if (redirect) { // Homeへリダイレクトする return <Redirect to={'/'} /> } return ( <main className="form-signin"> <form onSubmit={submit}> // submitをセット ... </form> </main> ) } export default Login |
だいたい登録処理の時と同じです。
ログイン情報をAxiosで送信し、リダイレクトフラグをたて、Home(ダッシュボード)画面へ遷移します。
違いがあるとすれば、「withCredentials」ですね。
API側では、ログイン情報をJWTのTokenに変換し、Cookieに保存します。Cookie情報を扱うために、このプロパティが必要のようです。
また、APIは「localhost:8000」、画面は「localhost:3000」とOriginが異なるため、API側に以下の設定が必要です。
1 2 3 4 5 6 7 8 9 10 11 12 |
// main.go ... func main() { ... // CORSの設定 app.Use(cors.New(cors.Config{ // 認証にcookieなどの情報を必要とするかどうか /AllowCredentials: true, })) ... } |
この設定がされていないと、「Access-Control-Allow-Origin」エラーが発生します。
Access to XMLHttpRequest at ‘http://localhost:8000/api/admin/login’ from origin’http://localhost:3000′ has been blocked by CORS policy:Response to preflight request doesn’t pass access control check:The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’when the request’s credentials mode is ‘include’. The credentials mode of requests initiatedby the XMLHttpRequest is controlled by the withCredentials attribute.
もし、ログインがうまくいかない場合は、設定に漏れがないか確認してください。
withCredentialsの共通化
前述の通り、Cookieを利用した認証機能をAPI側で実装しているため、axiosリクエスト全てにwithCredentialsを付与しなければなりません。
これは大変煩わしいので、withCredentialsプロパティを常にtrueにする設定をindex.tsxに入れたいと思います。
1 2 3 4 5 |
// src/index.tsx axios.defaults.withCredentials = true ... |
この変更に伴い、先ほど実装したSubmit処理のPOSTリクエストも以下のように変更します。
1 2 3 4 5 6 7 8 9 |
// ログイン情報を送信 await axios.post(loginUrl, { email: email, password: password // withCredentials // リクエストに Cookie を添えて送信する // API側ではCookieにTokenを保存している }) // withCredentialsを削除 |
検証
実際にログインできるか確認してみましょう。
前回の記事を参考に、ユーザー情報を登録してからログインしてみてください。
ログインURLは、「http://localhost:3000/login」です。
私は、「test@omega.com」Emailを持つユーザーを作成してあるので、それでログインします。


OKですね。
次回
次回は、ログイン・ログアウト機能を実装をしましょう。
Reactまとめ
参考書籍
ソースコード
ここまで実装したソースコードを下記に記載します。
Register.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
// pages/Register.tsx import {Component, SyntheticEvent} from "react"; import axios from "axios" import {User} from '../models/user' import {Redirect} from 'react-router-dom' class Register extends Component { firstName = '' lastName = '' email = '' password = '' passwordConfirm = '' registerUrl = 'register' state = { redirect: false } // SyntheticEvent // https://ja.reactjs.org/docs/events.html submit = async (e: SyntheticEvent) => { // formのデフォルトの挙動をキャンセルする // https://ja.reactjs.org/docs/handling-events.html e.preventDefault() const user = new User( this.firstName, this.lastName, this.email, this.password, this.passwordConfirm ) // フォーマットが合っていればクラスをそのまま渡せる await axios.post(this.registerUrl, user) // 送信に成功したらリダイレクトフラグを立てる this.setState({ redirect: true }) } render() { // ログイン画面へリダイレクト if (this.state.redirect) { return <Redirect to={'/login'} /> } return ( <main className="form-signin"> <form onSubmit={this.submit}> <h1 className="h3 mb-3 fw-normal">Please register</h1> <div className="form-floating"> <input className="form-control" placeholder="First Name" onChange={e => this.firstName = e.target.value} /> <label>First Name</label> </div> <div className="form-floating"> <input className="form-control" placeholder="Last Name" onChange={e => this.lastName = e.target.value} /> <label>Last Name</label> </div> <div className="form-floating"> <input type="email" className="form-control" placeholder="name@example.com" onChange={e => this.email = e.target.value} /> <label>Email address</label> </div> <div className="form-floating"> <input type="password" className="form-control" placeholder="Password" onChange={e => this.password = e.target.value} /> <label>Password</label> </div> <div className="form-floating"> <input type="password" className="form-control" placeholder="Password Confirm" onChange={e => this.passwordConfirm = e.target.value} /> <label>Password Confirm</label> </div> <button className="w-100 btn btn-lg btn-primary" type="submit">Submit</button> </form> </main> ) } } export default Register |
index.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// src/index.tsx import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import axios from 'axios' axios.defaults.baseURL = 'http://localhost:8000/api/admin/' axios.defaults.withCredentials = true ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals(); |
Login.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
// pages/Login.tsx import { SyntheticEvent, useState } from 'react' import '../Login.css' import axios from 'axios' import { Redirect } from 'react-router' const Login = () => { // ログイン情報 const [email, setEmail] = useState('') const [password, setPassword] = useState('') const loginUrl = 'login' const [redirect, setRedirect] = useState(false) const submit = async (e: SyntheticEvent) => { // formのデフォルトの挙動をキャンセル e.preventDefault() // ログイン情報を送信 await axios.post(loginUrl, { email: email, password: password // withCredentials // リクエストに Cookie を添えて送信する // API側ではCookieにTokenを保存している }) // リダイレクトフラグをTrue setRedirect(true) } if (redirect) { // Homeへリダイレクトする return <Redirect to={'/'} /> } return ( <main className="form-signin"> <form onSubmit={submit}> <h1 className="h3 mb-3 fw-normal">Please sign in</h1> <div className="form-floating"> <input type="email" className="form-control" id="floatingInput" placeholder="name@example.com" // Emailをセット onChange={e => setEmail(e.target.value)} /> <label htmlFor="floatingInput">Email address</label> </div> <div className="form-floating"> <input type="password" className="form-control" id="floatingPassword" placeholder="Password" // Passwordをセット onChange={e => setPassword(e.target.value)} /> <label htmlFor="floatingPassword">Password</label> </div> <button className="w-100 btn btn-lg btn-primary" type="submit">Sign in</button> </form> </main> ) } export default Login |
コメントを残す
コメントを投稿するにはログインしてください。