~~~~~~~~~~ (Contents) MERN ~~~~~~~~~~~
[MERN①] Express & MongoDB Setup
https://qiita.com/niyomong/private/3281af84486876f897f7
[MERN②]User API Routes & JWT Authentication
https://qiita.com/niyomong/private/c11616ff7b64925f9a2b
[MERN③] Profile API Routes
https://qiita.com/niyomong/private/8cff4e6fa0e81b92cb49
[MERN④] Post API
https://qiita.com/niyomong/private/3ce66f15375ad04b8989
[MERN⑤] Getting Started With React & The Frontend
https://qiita.com/niyomong/private/a5759e2fb89c9f222b6b
[MERN⑥] Redux Setup & Alerts
https://qiita.com/niyomong/private/074c27259924c7fd306b
[MERN⑦] React User Authentication
https://qiita.com/niyomong/private/37151784671eff3b92b6
[MERN⑧] Dashboard & Profile Management
https://qiita.com/niyomong/private/ab7e5da1b1983a226aca
[MERN⑨] Profile Display
https://qiita.com/niyomong/private/42426135e959c7844dcb
[MERN⑩] Posts & Comments
https://qiita.com/niyomong/private/19c78aea482b734c3cf5
[MERN11] デプロイ
https://qiita.com/niyomong/private/150f9000ce51548134ad
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. User Modelを作成
Modelフォルダ作成
Userモデルファイル作成
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
avatar: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = User = mongoose.model('user', UserSchema);
2. リクエスト & Bodyバリデーション
...
connectDB();
+ // Init Middleware
+ app.use(express.json({ extended: false }));
app.get('/', (req, res) => res.send('API Running'));
...
express-validator
const express = require('express');
const router = express.Router();
const { body, validationResult } = require('express-validator');
+ // @route POST api/users
// @desc Register user
// @access Public
router.post(
'/',
+ [
+ body('name', 'Name is required').not().isEmpty(),
+ body('email', 'Please include a valid email').isEmail(),
+ body(
+ 'password',
+ 'Please enter a password with 6 or more characters'
+ ).isLength({ min: 6 }),
+ ],
(req, res) => {
+ const errors = validationResult(req);
+ if (!errors.isEmpty()) {
+ return res.status(400).json({ errors: errors.array() });
+ }
res.send('User route');
}
);
module.exports = router;
POSTMANによるチェック
(nameのみ入力の場合)-> "400 Bad Request"(失敗の返答)
(name、 email、6桁passすべて入力した場合)-> "200 OK"(成功の返答)
User Registration
-> gravatarを追加
-> bcryptを追加
const express = require('express');
const router = express.Router();
+ const gravatar = require('gravatar');
+ const bcrypt = require('bcryptjs');
const { body, validationResult } = require('express-validator');
const User = require('../../models/User');
// @route POST api/users
// @desc Register user
// @access Public
router.post(
'/',
[
body('name', 'Name is required').not().isEmpty(),
body('email', 'Please include a valid email').isEmail(),
body(
'password',
'Please enter a password with 6 or more characters'
).isLength({ min: 6 }),
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
+ const { name, email, password } = req.body;
+ try {
+ let user = await User.findOne({ email });
+ if (user) {
+ // See if user exists
+ return res.status(400).json({ erros: [{ msg: 'User already exists' }] });
+ }
+ // Get users gravatar
+ const avatar = gravatar.url(email, {
+ s: '200',
+ r: 'pg',
+ d: 'm',
+ });
+ user = new User({ name, email, avatar, password });
+ // Encrypt password
+ const salt = await bcrypt.genSalt(10);
+ user.password = await bcrypt.hash(password, salt);
+ await user.save();
+ // Return jsonwebtoken
+ res.send('User registered');
+ } catch (err) {
+ console.error(err.message);
+ res.status(500).send('Server error');
+ }
+ }
);
module.exports = router;
POSTMANでPost
MongoDB Atlasに格納された!
登録した後、再度Postをすると
3. JWT (jsonWebToken)を実行
JWTの説明:https://github.com/auth0/node-jsonwebtoken
-> jwtを設置
-> configを設置
...
const bcrypt = require('bcryptjs');
+ const jwt = require('jsonwebtoken');
+ const config = require('config');
const { body, validationResult } = require('express-validator');
...
// Encrypt password
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
// Return jsonwebtoken
+ const payload = {
+ user: {
+ id: user.id,
+ },
+ };
+ jwt.sign(
+ payload,
+ config.get('jwtSecret'),
+ { expiresIn: 360000 },
+ (err, token) => {
+ if (err) throw err;
+ res.json({ token });
+ }
);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
...
mongoDB -> _id
mongoose -> id
{
"mongoURI": "xxx",
+ "jwtSecret": "xxxxxtoken"
}
3. Authミドルウェアをカスタマイズ & JWT証明
middleware/auth.jsファイル作成
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function (req, res, next) {
//Get token from header
const token = req.header('x-auth-token');
// Check if not token
if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' });
}
//Verify token
try {
const decoded = jwt.verify(token, config.get('jwtSecret'));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: 'Token is not valid' });
}
};
const express = require('express');
const router = express.Router();
+ const auth = require('../../middleware/auth');
+ const User = require('../../models/User');
// @route GET api/auth
// @desc Test route
// @access Public
+ router.get('/', auth, async (req, res) => {
+ try {
+ const user = await User.findById(req.user.id).select('-password'); //passwordは除くUserデータを取得
+ res.json(user);
+ } catch (err) {
+ console.error(err.message);
+ res.status(500).send('Server Error');
+ }
});
module.exports = router;
POSTMAN
Headersに
-> KEY: x-auth-token
-> VALUE: POST /api/usersした時にJWTでレスのあったTokenをペースト
4. ユーザー認証 & ログイン
const express = require('express');
const router = express.Router();
+ const bcrypt = require('bcryptjs');
const auth = require('../../middleware/auth');
+ const jwt = require('jsonwebtoken');
+ const config = require('config');
+ const { body, validationResult } = require('express-validator');
const User = require('../../models/User');
// @route GET api/auth
// @desc Test route
// @access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
//以下、routes/api/user.jsからコピペして修正
+ // @route POST api/auth
+ // @desc Authenticate user & get token
+ // @access Public
+ router.post(
+ '/',
+ [
+ body('email', 'Please include a valid email').isEmail(),
+ body('password', 'Password is required').exists(),
+ ],
+ async (req, res) => {
+ const errors = validationResult(req);
+ if (!errors.isEmpty()) {
+ return res.status(400).json({ errors: errors.array() });
+ }
+ const { email, password } = req.body;
+ try {
+ let user = await User.findOne({ email });
+ if (!user) {
+ // See if user exists
+ return res
+ .status(400)
+ .json({ erros: [{ msg: 'Invalid Credentials' }] });
+ }
+ const isMatch = await bcrypt.compare(password, user.password);
+ if (!isMatch) {
+ return res
+ .status(400)
+ .json({ erros: [{ msg: 'Invalid Credentials' }] });
+ }
+ // Return jsonwebtoken
+ const payload = {
+ user: {
+ id: user.id,
+ },
+ };
+ jwt.sign(
+ payload,
+ config.get('jwtSecret'),
+ { expiresIn: 360000 },
+ (err, token) => {
+ if (err) throw err;
+ res.json({ token });
+ }
+ );
+ } catch (err) {
+ console.error(err.message);
+ res.status(500).send('Server error');
+ }
+ }
);
module.exports = router;