diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74688dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +md/ \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..9ac9de3 --- /dev/null +++ b/config.js @@ -0,0 +1,4 @@ +module.exports = { + 'secret': 'learnRestApiwithNickjs', // used when we create and verify JSON Web Tokens + 'database': 'mongodb://localhost:27017/test' // 填写本地自己 mongodb 连接地址,xxx为数据表名 +}; diff --git a/index.js b/index.js new file mode 100644 index 0000000..6da890a --- /dev/null +++ b/index.js @@ -0,0 +1,25 @@ +const express = require('express'); +const app = express(); +const bodyParser = require('body-parser');// 解析body字段模块 +const morgan = require('morgan'); // 命令行log显示 +const mongoose = require('mongoose'); +const passport = require('passport');// 用户认证模块passport +const Strategy = require('passport-http-bearer').Strategy;// token验证模块 +const routes = require('./routes'); +const config = require('./config'); + +let port = process.env.PORT || 8080; + +app.use(passport.initialize());// 初始化passport模块 +app.use(morgan('dev'));// 命令行中显示程序运行日志,便于bug调试 +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); // 调用bodyParser模块以便程序正确解析body传入值 + +routes(app); + +mongoose.Promise = global.Promise; +mongoose.connect(config.database); // 连接数据库 + +app.listen(port, () => { + console.log('listening on port : ' + port); +}) diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..3db131c --- /dev/null +++ b/models/user.js @@ -0,0 +1,50 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const bcrypt = require('bcrypt'); + +const UserSchema = new Schema({ + name: { + type: String, + unique: true, + require: true + }, + password: { + type: String, + require: true + }, + token: { + type: String + } +}); + +// 添加用户保存时中间件对password进行bcrypt加密,这样保证用户密码只有用户本人知道 +UserSchema.pre('save', function (next) { + var user = this; + if (this.isModified('password') || this.isNew) { + bcrypt.genSalt(10, function (err, salt) { + if (err) { + return next(err); + } + bcrypt.hash(user.password, salt, function (err, hash) { + if (err) { + return next(err); + } + user.password = hash; + next(); + }); + }); + } else { + return next(); + } +}); +// 校验用户输入密码是否正确 +UserSchema.methods.comparePassword = function(passw, cb) { + bcrypt.compare(passw, this.password, (err, isMatch) => { + if (err) { + return cb(err); + } + cb(null, isMatch); + }); +}; + +module.exports = mongoose.model('User', UserSchema); diff --git a/package.json b/package.json new file mode 100644 index 0000000..58635ee --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "auth", + "version": "1.0.0", + "description": "基于node.js+express+mongodb的restful api开发用户模型认证相关", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Nickj", + "license": "ISC", + "dependencies": { + "bcrypt": "^0.8.7", + "body-parser": "^1.15.2", + "express": "^4.14.0", + "jsonwebtoken": "^7.1.9", + "mongoose": "^4.7.1", + "morgan": "^1.7.0", + "passport": "^0.3.2", + "passport-http-bearer": "^1.0.1" + } +} diff --git a/passport.js b/passport.js new file mode 100644 index 0000000..0c53f46 --- /dev/null +++ b/passport.js @@ -0,0 +1,23 @@ +const passport = require('passport'); +const Strategy = require('passport-http-bearer').Strategy; + +const User = require('./models/user'); +const config = require('./config'); + +module.exports = function(passport) { + passport.use(new Strategy( + function(token, done) { + User.findOne({ + token: token + }, function(err, user) { + if (err) { + return done(err); + } + if (!user) { + return done(null, false); + } + return done(null, user); + }); + } + )); +}; diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..c58e297 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,7 @@ +module.exports = (app) => { + app.get('/', (req, res) => { + res.json({ message: 'hello index!'}); + }); + + app.use('/api', require('./users')); // 在所有users路由前加/api +}; diff --git a/routes/users.js b/routes/users.js new file mode 100644 index 0000000..c0839ab --- /dev/null +++ b/routes/users.js @@ -0,0 +1,75 @@ +const express = require('express'); +const User = require('../models/user'); +const jwt = require('jsonwebtoken'); +const config = require('../config'); +const passport = require('passport'); +const router = express.Router(); + +require('../passport')(passport); + +// 注册账户 +router.post('/signup', (req, res) => { + if (!req.body.name || !req.body.password) { + res.json({success: false, message: '请输入您的账号密码.'}); + } else { + var newUser = new User({ + name: req.body.name, + password: req.body.password + }); + // 保存用户账号 + newUser.save((err) => { + if (err) { + return res.json({success: false, message: '注册失败!'}); + } + res.json({success: true, message: '成功创建新用户!'}); + }); + } +}); + +// 检查用户名与密码并生成一个accesstoken如果验证通过 +router.post('/user/accesstoken', (req, res) => { + User.findOne({ + name: req.body.name + }, (err, user) => { + if (err) { + throw err; + } + if (!user) { + res.json({success: false, message:'认证失败,用户不存在!'}); + } else if(user) { + // 检查密码是否正确 + user.comparePassword(req.body.password, (err, isMatch) => { + if (isMatch && !err) { + var token = jwt.sign({name: user.name}, config.secret,{ + expiresIn: 10080 + }); + user.token = token; + user.save(function(err){ + if (err) { + res.send(err); + } + }); + res.json({ + success: true, + message: '验证成功!', + token: 'Bearer ' + token, + name: user.name + }); + } else { + res.send({success: false, message: '认证失败,密码错误!'}); + } + }); + } + }); +}); + +// passport-http-bearer token 中间件验证 +// 通过 header 发送 Authorization -> Bearer + token +// 或者通过 ?access_token = token +router.get('/user/user_info', + passport.authenticate('bearer', { session: false }), + function(req, res) { + res.json({username: req.user.name}); +}); + +module.exports = router;