画面
App.js
パスとページをここで定義する
App.js
import { Routes, Route, BrowserRouter } from 'react-router-dom';
import LoginPage from './components/LoginPage';
import Home from './components/Home';
import LoginError from './components/LoginError';
import NotFoundPage from './components/NotFoundPage';
function App() {
return (
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/home" element={<Home />} />
<Route path="/loginerror" element={<LoginError />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
LoginPage.js
Node.js側にリクエストを送り、結果に応じてログインページか失敗ページへ遷移。
LoginPage.js
// npm install react-router-dom
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
function LoginPage() {
const [username, setUsername] = useState('');//var,letで宣言して直接代入するとReactに状態の変化を伝えられない
const [password, setPassword] = useState('');
const navigate = useNavigate();
// submit時(ログインボタン押下時)
function handleLogin(e) {
e.preventDefault();// 画面の刷新を止める。フォーム送信時初期状態では画面が刷新されReactの理念と異なる。状態も初期化されてしまう。
try {
fetch('http://localhost:3001/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),//JavaScriptのオブジェクトをJSON形式の文字列に変換
})
// 返り値をJSON形式に変換
.then(function(response) { // responseにはサーバからの返り値が入る
return response.json(); // jsonへ変換(Node.jsからjsonを返していても変換が必要)
})
// 変換されたデータを確認
.then(function(data) { // dataにはresponse.json()が入る
if (data.success) {
navigate('/home'); // ログイン成功
} else {
navigate('/loginerror'); // ログイン失敗
}
})
// エラー発生時の処理
.catch(function(error) {
console.error('Login error:', error);
navigate('/loginerror');
});
} catch (error) {
console.error('Login error:', error);
navigate('/loginerror');
}
}
// ユーザ名が変更されたら状態を更新する
function handleUsernameChange(e) {
setUsername(e.target.value);
}
// パスワードが変更されたら状態を更新する
function handlePasswordChange(e) {
setPassword(e.target.value);
}
return (
<div style={{ padding: '20px' }}>
<h2>Login</h2>
<form onSubmit={handleLogin} style={{ display: 'flex', flexDirection: 'column', gap: '10px', maxWidth: '300px' }}>
<input
type="text"
placeholder="Username"
value={username}
onChange={handleUsernameChange}
required
style={{ padding: '8px' }}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={handlePasswordChange}
required
style={{ padding: '8px' }}
/>
<button type="submit" style={{ padding: '10px', backgroundColor: '#007bff', color: 'white', border: 'none' }}>
Login
</button>
</form>
</div>
);
}
export default LoginPage;
サーバ
ユーザ名とパスワードが一致するかを確認する
login.js
//npm init -y
//npm install express cors
const express = require('express'); // Webサーバーを構築する土台 今回だとpost,listenを使用
const cors = require('cors'); // これが無いとip+ポート番号が違うだけで通信が出来ない。例:画面3000、サーバ3001も不可
const app = express();// app変数にサーバーインスタンスが入る
const PORT = 3001;
app.use(cors());
app.use(express.json());
// ユーザ一覧(将来はユーザ名+HATH値をDB保存予定)
const users = [
{ username: 'admin', password: 'password123' },
{ username: 'user', password: 'userpass' }
];
// POST処理
app.post('/login', function(req, res) {
const { username, password } = req.body;
const user = users.find(function(u) {
// この関数は各ユーザーに対して実行される(users[i].usernameとしてfor文で回しても同じ)
return u.username === username && u.password === password;
});
if (user) { //ユーザ存在
res.json({
success: true,
message: 'Login successful',
user: { username: user.username }
});
} else { //ユーザ不存在
res.status(401).json({
success: false,
message: 'Invalid credentials'
});
}
});
app.listen(PORT, function() {
console.log('Server running on port ' + PORT);
});
パスワード暗号化
次はハッシュ値を使って認証するようにする。
https://qiita.com/earthen94/items/8f4993279cd2894dcf4a