昨天我們已經實作了登入和註冊API,並了解JWT整個運作過程。
接著我們要來開發User相關的API和auth middleware開發

在controllers資料夾底下建立users-controller.js
//users-controller.js
const HttpError = require('../models/http-error');
const User = require('../models/User');  //記得引入User model
//取得使用者資料
exports.getUserProfile = async (req, res) => {
    try {
        const userId = req.params.userId;
        const user = await User.findById(userId);
        if (!user) {
            return next(new HttpError('查無此使用者', 404)); 
        }
        // 取得使用者資料(記得不可以回傳密碼)
        const userProfile = {
            fullName: user.fullName,
            email: user.email,
            joinDate: user.joinDate,
            bio: user.bio,
            profileImage: user.profileImage
        };
        res.json(userProfile);
        
    } catch (error) {
        next(new HttpError('Server error', 500));
    }
};
//更新使用者資料
exports.updateUserProfile = async (req, res) => {
    try {
        const userId = req.params.userId;
        const { fullName, password, bio, profileImage } = req.body;
        const updatedData = {
            ...(fullName && { fullName }),
            ...(password && { password }),
            ...(bio && { bio }),
            ...(profileImage && { profileImage })
        };
        const updatedUser = await User.findByIdAndUpdate(userId, updatedData, { new: true });
        if (!updatedUser) {
            return next(new HttpError('查無此使用者', 404)); 
        }
        const updatedProfile = {
            fullName: updatedUser.fullName,
            email: updatedUser.email,
            joinDate: updatedUser.joinDate,
            bio: updatedUser.bio,
            profileImage: updatedUser.profileImage
        };
        res.json(updatedProfile);
        
    } catch (error) {
        next(new HttpError('Server error', 500));
    }
};
接著在routes資料夾底下建立users-routes.js,並把剛剛建立user-controller.js引入
//users-routes.js
const express = require('express');
const router = express.Router();
const userControllers = require('../../controllers/users-controller');
//@router GET api/users/:userId/profile
//@desc GET 取得使用者資訊
//@access Public
router.get('/:userId/profile', userControllers.getUserProfile);
//@router PUT api/users/:userId/profile
//@desc PUT 修改使用者資料
//@access Public
router.put('/:userId/profile', userControllers.updateUserProfile);
module.exports = router;
最後在server.js引入users-routes.js
//server.js
const express = require('express');
const connectDB = require('./config/db');
const app = express();
const bodyParser = require('body-parser');
const users = require('./routes/api/users-route'); //引入users-routes.js
const auth = require('./routes/api/auth-route');
const posts = require('./routes/api/posts-route');
connectDB();
app.use(bodyParser.json());
app.use('/api/users', users);
...(略)
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
更新使用者資料
取得使用者資料
昨天我們有介紹authorization(授權)是什麼,並且也實作了JWT(JSON Web Token)。
❓稍微再複習一下token是什麼
在前後端溝通時,token 就是前後端溝通用的憑證。前端若要和後端伺服器請求任何資料時,都必須要在發出去的請求中帶入這個 token 憑證,如果沒有攜帶憑證,或是憑證有誤的話,伺服器都不會回應請求。這個機制也是避免有未經授權的訪問和資料的竄改和偽造。
那當我們呼叫API時,該如何去驗證這個API有沒有攜帶合法憑證;若有攜帶合法憑證又該如何授權?
👉這時就要建立Auth middleware,來為我們檢驗這個API是否有攜帶或有合法的憑證
🛠️運作概念如下:
如果認證或授權失敗,Auth middleware 通常會直接回應錯誤。若認證成功,它會解析出的使用者資訊附加到請求上,然後將控制權傳遞給下一個中介軟體或路由處理程式。
建立middleware資料夾,並在底下新增auth.js檔案
//auth.js
const jwt = require('jsonwebtoken');
const config = require('config');  //存取設置的私鑰
module.exports = function(req, res, next) {
    //從請求標頭中提取JWT(JSON Web Token)
    const bearerHeader =  req.header('Authorization');
    // 如果沒有則回傳錯誤
    if(!bearerHeader){
        return res.status(401).json({msg: 'No token, authorization denied'});
    }
    const bearer = bearerHeader.split(' ');
    const token = bearer[1];
    
    //檢驗憑證
    try{
        //判斷提供的憑證是否有效
        const decoded = jwt.verify(token,config.get('jwtSecret'));
        // 將解析出來的使用者資訊加到請求上
        req.user = decoded.user; 
        // 轉到下一個middleware或路由處理程式
        next(); 
    }
    catch(err){
        res.status(401).json({msg: '無效的憑證'});
    }
}
完成剛剛的auth middleware後,我們就要在post和user api上加上這個中介軟體,避免未經授權的使用者去取得這些敏感資料或者進行非法的操作。
const express = require("express");
const router = express.Router();
const postControllers = require("../../controllers/posts-controller");
const auth = require("../../middleware/auth"); //引入我們剛剛的auth middleware
//@router POST /api/posts
//@desc 新增文章
//@access Public
router.post("/", auth, postControllers.createPost); //在function中間加入auth
//@router  GET api/posts/:postId
//@desc 取得單一文章
//@access Public
router.get("/:postId", auth, postControllers.getPost);
//@router PUT /api/posts/:postId
//@desc 更新文章
//@access Public
router.put("/:postId", auth, postControllers.updatePost);
//@router DELETE api/posts
//@desc 刪除文章
//@access Public*/
router.delete("/:postId",auth,postController.deletePost);
module.exports = router;
const express = require('express');
const router = express.Router();
const userControllers = require('../../controllers/users-controller');
const auth = require("../../middleware/auth"); //引入我們剛剛的auth middleware
//@router GET api/users/:userId/profile
//@desc GET 取得使用者資訊
//@access Public
router.get('/:userId/profile', auth, userControllers.getUserProfile);
//@router PUT api/users/:userId/profile
//@desc PUT 修改使用者資料
//@access Public
router.put('/:userId/profile', auth, userControllers.updateUserProfile);
module.exports = router;