node試水——express+mlab登入註冊
阿新 • • 發佈:2019-01-05
express+mlab登入註冊
簡介和思路
- 使用express作為node框架,mlab作線上資料庫,postman作為除錯介面工具;
- 註冊時匹配唯一郵箱,錄入使用者名稱、密碼(用bcrypt加密過)、郵箱、頭像(獲取gravatar公認頭像),儲存資料庫成功後返回使用者資訊;
- 登入時匹配使用者名稱和密碼,匹配成功後返回Bearer token令牌;
- 訪問一個介面,校驗傳入的authorization是否和登入時的token匹配,匹配通過則返回介面資料,否則響應未通過認證。
github
檔案目錄
流程演示
註冊成功後返回使用者資訊:
註冊時郵箱重複後返回錯誤資訊:
登入成功後返回token:
密碼錯誤返回錯誤資訊:
訪問一個返回使用者資訊的介面,token驗證通過才能獲取到:
token驗證不通過則預設會返回驗證失敗:
用到的依賴和工具
- 工具:postman 傳送請求和接收響應,用於調介面
- “bcrypt”: “^3.0.2” 對註冊密碼進行加密
- “body-parser”: “^1.18.3” 對post請求的請求體進行解析
- “express”: “^4.16.4” nodejs框架,設定中介軟體響應HTTP請求,定義路由執行HTTP請求動作,給HTML頁面傳遞引數
- “gravatar”: “^1.6.0” 全球公認頭像
- “jsonwebtoken”: “^8.3.0” 跨域認證解決方案,用於生成token令牌,服務端認定使用者身份
- “mongoose”: “^5.3.8” 對mongodb進行便捷操作的物件模型工具
- “passport”: “^0.4.0” 用於驗證登入資訊,如果token通過才能訪問介面
- “passport-jwt”: “^4.0.0”
server.js
功能:配置/連線資料庫,配置訪問API的中介軟體,配置/監聽埠號等等。
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require( 'passport');
// 介面api
const users = require('./routers/api/users');
const profiles = require('./routers/api/profiles');
const app = express();
// 使用body-parser中介軟體
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 使用中介軟體使用users,訪問/api/users時獲取到users
app.use('/api/users', users);
app.use('/api/profiles', profiles);
// 連結資料庫
const db = require('./config/keys').mongoURL;
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => {
console.log('connect');
})
.catch(err => {
console.log(err);
});
// 初始化passport
// passport的配置
app.use(passport.initialize());
require('./config/passport')(passport);
// 訪問主頁時給頁面傳送資料
app.get('/', (req, res) => {
res.send('hello world');
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log('server start');
});
users.js
功能:介面程式碼,配置router
const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const gravatar = require('gravatar');
const keys = require('../../config/keys');
const passport = require('passport');
const User = require('../../models/User');
// $router POST api/users/register
// @desc 返回請求的json資料
// @access public
router.post('/register', (req, res) => {
// 查詢一條記錄
User.findOne({
email: req.body.email
}).then(user => {
if (user) {
return res.status(400).json('郵箱已被註冊');
} else {
var avatar = gravatar.url('req.body.email', { s: '200', r: 'pg', d: 'mm' });
const newUser = new User({
avatar,
name: req.body.name,
email: req.body.email,
password: req.body.password,
identity: req.body.identity
});
// 用bcrypt對密碼進行加密
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) {
throw err;
}
// hash為加密後的密碼
newUser.password = hash;
// 呼叫儲存方法
newUser
.save()
.then(user => {
res.json(user);
})
.catch(err => {
console.log(err);
});
});
});
}
});
});
// $router POST api/users/login
// @desc 返回token jwt password
// @access public
router.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
User.findOne({ email }).then(user => {
if (!user) {
return res.status(404).json('使用者不存在');
}
// 密碼匹配
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
// 規則,加密名字,過期時間,回撥
const rule = {
id: user.id,
name: user.name,
avatar: user.avatar,
identity: user.identity
};
// 登入成功後返回token,相當於一個令牌,只有令牌校驗成功,才可以獲取想要的資料
jwt.sign(rule, keys.secretOrKey, { expiresIn: 3600 }, (err, token) => {
if (err) {
throw err;
}
res.json({
success: true,
// 必須加Bearer
token: 'Bearer ' + token
});
});
// res.json({ msg: 'success' });
} else {
return res.status(404).json('密碼錯誤');
}
});
});
});
// $router GET api/users/current
// @desc 返回current user
// @access private
router.get('/current', passport.authenticate('jwt', { session: false }), (req, res) => {
res.json({
id: req.user.id,
name: req.user.name,
email: req.user.email,
identity: req.user.identity
});
});
module.exports = router;
User.js
功能:配置mongoose的模型
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// 建立模型和所需要的欄位
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
identity: {
type: String,
required: true
},
data: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model('users', UserSchema);
passport.js
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = mongoose.model('users');
const keys = require('../config/keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
// passport驗證token
module.exports = passport => {
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
User.findById(jwt_payload.id)
.then(user => {
if (user) {
return done(null, user);
} else {
return done(null, false);
}
})
.catch(err => {
console.log(err);
});
})
);
};
keys.js
module.exports = {
//註冊mlab之後,create生成的地址
mongoURL: 'mongodb://manager-web:[email protected]:47233/resful-api-prod',
secretOrKey: 'secret'
};