最近学习React 自己的在线购物网站做的差不多了,需要开始用户登陆,生成订单,然后用palpay付款了。于是开始自己搭建一个Node.js 的后端服务器。
安装node.js mongodb 就不再说了,直接开始从代码开始说起吧
package.json 可以看出来要安装的包:
使用了以下包:
{
"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了。