从零开始用Node.js 和Mongodb 写一个JWT Auth Server - 用户认证服务器

    科技2025-07-07  16

    最近学习React 自己的在线购物网站做的差不多了,需要开始用户登陆,生成订单,然后用palpay付款了。于是开始自己搭建一个Node.js 的后端服务器。

    安装node.js mongodb 就不再说了,直接开始从代码开始说起吧

    package.json 可以看出来要安装的包:

    使用了以下包:

    express  Web框架mongoose 数据库连接库morgan morgan是express默认的日志中间件ody-parser 是非常常用的一个express中间件,作用是对post请求的请求体进行解析。nodemon 可以动态修改代码应用node.jsbcrypt-nodejs 对于密码加密jwt-simple 创建JWTpassport   验证登陆passport-jwt  (看名字应该知道了,不用再说了吧)passport-local  //通过用户名密码验证登陆 { "name": "server", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "nodemon index.js" }, "author": "", "license": "ISC", "dependencies": { "bcrypt-nodejs": "0.0.3", "body-parser": "^1.19.0", "express": "^4.17.1", "jwt-simple": "^0.5.6", "mongoose": "^5.10.8", "morgan": "^1.10.0", "nodemon": "^2.0.4", "passport": "^0.4.1", "passport-jwt": "^4.0.0", "passport-local": "^1.0.0" } }

    下面建立程序。对于程序不再单独说明了,请看注解。

    程序主文件

    index.js

    const express = require('express') const http = require('http'); const bodyParser = require('body-parser'); const morgan = require('morgan'); const app = express(); const router = require('./router'); const mongoose = require('mongoose'); //DB Setup mongoose.connect('mongodb://localhost:27017/auth',{useUnifiedTopology:true,useNewUrlParser:true}); //you have to change to your mongodb url //App Setup app.use(morgan('combined')); app.use(bodyParser.json({type:'*/*'})); router(app); //Server Setup const port = process.env.PORT || 3090; const server = http.createServer(app); server.listen(port); console.log("Server listening on :",port);

    config.js  // 这个文件是存本地密钥的,字符串是随便敲的,写什么都可以。一般正式的项目不要加入到git 里面上传,只放本地保存。

    // Hold application secrets and config module.exports = { secret:'a;lskdjf;laskjf;lskjewroiudf' }

    router.js // 路由文件可以根据自己需要继续扩展,我写了主页要求带上jwt访问的要求

    const Authentication = require('./controllers/authentication'); const passportService = require('./services/passport'); const passport = require('passport'); const requireAuth = passport.authenticate('jwt',{session:false}); const requireSignin = passport.authenticate('local',{session:false}); module.exports = function (app) { app.get('/',requireAuth, (req,res) => { res.send({Login:'你已经登陆进来了!'}); }); app.post('/signin', requireSignin, Authentication.signin); app.post('/signup', Authentication.signup); }

    controllers/authentication.js 这里是控制器

    const jwt = require('jwt-simple'); const User = require('../models/user'); const config = require('../config'); function tokenForUser(user) { const timestamp = new Date().getTime(); return jwt.encode({sub: user.id, iat: timestamp}, config.secret); } exports.signin = function (req,res,next){ //User has already had their email and password auth'd //We just need to give them a token res.send({token:tokenForUser(req.user)}) } exports.signup = function (req, res, next) { const {email, password} = req.body; if (!email || !password) { return res.status(422).send({error: 'You must provide email and password '}); } //See if a user with the given email exists User.findOne({email}, function (err, existingUser) { if (err) { return next(err); } //If a user with email does exist, return an error if (existingUser) { return res.status(422).send({error: 'Email is in use'}); } //If a user with email does NOT exist, create and save user record const user = new User({email, password}); user.save((err) => { if (err) { return next(err); } // Respond to request indicating the user was created console.log("now the user passwordis", user.password); res.json({token:tokenForUser(user)}); }); }); }

    models/user.js 这里是用户类

    const mongoose = require("mongoose"); const Schema = mongoose.Schema; const bcrypt = require('bcrypt-nodejs'); //Define our model const userSchema = new Schema({ email: {type: String, unique:true, lowercase:true }, password: String, }); // On Save Hook, encrypt password; //Before saving a model, run this function userSchema.pre('save', function(next){ // HERE IS MUST NOT TO USING ARROW FUNCTION const user = this; //generate a salt then run callback bcrypt.genSalt(10, (err,salt) => { if(err){return next(err);} //hash(encrypt) our password using the salt bcrypt.hash(user.password,salt,null, (err,hash) => { if(err){return next(err);} //overwrite plain text password user.password = hash; next(); }) }) }) userSchema.methods.comparePassword =function (candidatePassword,callback) { // HERE IS MUST NOT TO USING ARROW FUNCTION bcrypt.compare(candidatePassword,this.password, (err,isMatch) => { if(err){return callback(err);} callback(null,isMatch); }) } //Create the model class const ModelClass = mongoose.model('user',userSchema); //Export the model module.exports = ModelClass;

    services/passport.js 这里是密码加密,数据库里存储的密码不可以是明码,就是这样

    const passport = require('passport'); const User = require('../models/user'); const config = require('../config'); const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; const LocalStrategy = require('passport-local'); // Create local strategy const localOptions = {usernameField:'email'} const localLogin = new LocalStrategy(localOptions, (email,password,done) => { // Verify this email and password, call done with the user // if it's the correct email and password // otherwise, call done with false User.findOne({email}, (err,user) => { if(err){ return done(err);} if(!user){return done(null,false);} //compare passwords - is password equal to user.password? user.comparePassword(password, (err,isMath) => { if(err){return done(err);} if(!isMath){return done(null,false);} return done(null,user); }); }); }) // Setup options for JWT Strategy const jwtOptions = { jwtFromRequest:ExtractJwt.fromHeader('authorization'), secretOrKey:config.secret }; // Create JWT strategy const jwtLogin = new JwtStrategy(jwtOptions, (payload,done) => { // See is the user ID in the payload exists in our database // if it does, call 'done' with that other // otherwise, call done without a user object User.findById(payload.sub, (err,user) => { if(err){return done(err,false);} if(user){ done(null,user); }else{ done(null,false); } }) }) // Tell passport to use this strategy passport.use(jwtLogin); passport.use(localLogin);

    运行起来以后,就可以用postman来进行singup 然后复制得到的token ,访问 / 的时候再Headers 里面增加authorization,value复制token过来, 记得是get操作。

    singup,singin 都是post操作,直接通过,http://localhost:3090/signin 和 http://localhost:3090/signup  send request, set  body ---> raw ---->  json

    按照下面格式写

    { "email":"1232TEST@abc.com", "password":"123123" }

    OK, 如果一切顺利,你已经做好一个非常安全的用户注册登陆api了。

     

     

    Processed: 0.011, SQL: 8