All Projects → Nicksapp → Nauth Restful Api

Nicksapp / Nauth Restful Api

Node.js+Mongoose的RestfulApi的用户token权限验证(just a demo)

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Nauth Restful Api

docker-node-express-boilerplate
Boilerplate for quickly bootstrapping production-ready RESTful APIs / microservices
Stars: ✭ 113 (-27.1%)
Mutual labels:  mongoose, restful-api
yelp-camp
A Node.js web application project from the Udemy course - The Web Developer Bootcamp by Colt Steele
Stars: ✭ 36 (-76.77%)
Mutual labels:  mongoose, restful-api
dhiwise-nodejs
DhiWise Node.js API generator allows you to instantly generate secure REST APIs. Just supply your database schema to DhiWise, and a fully documented CRUD APIs will be ready for consumption in a few simple clicks. The generated code is clean, scalable, and customizable.
Stars: ✭ 224 (+44.52%)
Mutual labels:  mongoose, restful-api
nestjs-rest-sample
NestJS RESTful APIs Sample
Stars: ✭ 204 (+31.61%)
Mutual labels:  mongoose, restful-api
Nodepress
😎 RESTful API service for Blog/CMS, powered by @nestjs
Stars: ✭ 829 (+434.84%)
Mutual labels:  restful-api, mongoose
react-nodejs-mongodb-crud
👨‍💻 Fullstack web app built with MongoDB, NodeJs, React and Redux. Features: Protected routes client/server side, MaterialUI layout
Stars: ✭ 91 (-41.29%)
Mutual labels:  mongoose, restful-api
NodeRestApi
Node.js, Express.js and MongoDB REST API App
Stars: ✭ 38 (-75.48%)
Mutual labels:  mongoose, restful-api
Sinn Server
an node server for sinn,that based on of nodejs,koa2,mongoose,docker,nginx,es6/7,Resful API,阿里云 http://servertest.boyagirl.com/
Stars: ✭ 228 (+47.1%)
Mutual labels:  restful-api, mongoose
Jianshu
仿简书nx+nodejs+nestjs6+express+mongodb+angular8+爬虫
Stars: ✭ 296 (+90.97%)
Mutual labels:  restful-api, mongoose
server-next
😎 The next generation of RESTful API service and more for Mix Space, powered by @nestjs.
Stars: ✭ 43 (-72.26%)
Mutual labels:  mongoose, restful-api
node-server-template
This is Node.js server tidy template / boilerplate with Express (with asyncified handlers, custom error handler) framework and MongoDb. The server use ES6 and above. On different branches you can see different techniques' and technologies' usage, such as Kafka, nodemailer, file download... You also can find postman collections.
Stars: ✭ 116 (-25.16%)
Mutual labels:  mongoose, restful-api
Ecommerce Nodejs
Ecommerce application back-end codes
Stars: ✭ 97 (-37.42%)
Mutual labels:  restful-api, mongoose
restgoose
Model-driven REST API framework using decorators
Stars: ✭ 28 (-81.94%)
Mutual labels:  mongoose, restful-api
Node Express Mongoose Passport Jwt Rest Api Auth
Node, express, mongoose, passport and JWT REST API authentication example
Stars: ✭ 146 (-5.81%)
Mutual labels:  restful-api, mongoose
dhan-gaadi
A complete online bus reservation system (Node, React, Mongo, NextJS, ReactNative)
Stars: ✭ 207 (+33.55%)
Mutual labels:  mongoose, restful-api
node-server
(@nestjs refactoring)⚡️My personal website's api server, a RESTful application that powered by @eggjs
Stars: ✭ 17 (-89.03%)
Mutual labels:  mongoose, restful-api
Nestjs Mongoose Crud
Nest.js crud module for mongoose models without `nestjsx/crud`
Stars: ✭ 164 (+5.81%)
Mutual labels:  restful-api, mongoose
express-typescript-mongoose-starter
A starter for Node JS, Express, Typescript, Mongoose application
Stars: ✭ 22 (-85.81%)
Mutual labels:  mongoose, restful-api
Appy Backend
A user system to bootstrap your app.
Stars: ✭ 96 (-38.06%)
Mutual labels:  restful-api, mongoose
Nodejs Rest Api Project Structure Express
Nodejs project structure practices for building RESTful APIs using Express framework and MongoDB.
Stars: ✭ 134 (-13.55%)
Mutual labels:  restful-api, mongoose

Node.js+Mongoose的RestfulApi的用户token权限验证

关于安全性方面的建议

可以参考这篇总结 开发安全的 API 所需要核对的清单

安装

git clone https://github.com/Nicksapp/nAuth-restful-api.git

运行

npm install

具体数据库配置信息在config.js中设置

整体构架

开发前先进行我们设计的构想

  • 路由设计

    • POST /api/signup: 用户注册
    • POST /api/user/accesstoken: 账号验证,获取token
    • GET /api/user/user_info: 获得用户信息,需验证
  • user 模型设计

    • name : 用户名
    • password: 密码
    • token: 验证相关token

关于RESTful API

网上已经有了很多关于RESTful的介绍,我这里也不过多重复了。想说的就是它的主要作用,就是对于现如今的网络应用程序,分为前端和后端两个部分,然而当前的发展趋势就是应用平台需求的扩大(IOS、Android、Webapp等等)

因此,就需要一种统一的机制,方便不同的应用平台的前端设备与后端进行通信,也就是前后端的分离。这导致了API架构的流行,甚至出现"API First"的设计思想。RESTful API则是目前比较成熟的一套互联网应用程序的API设计理论。

技术栈

使用Node.js上的Express框架进行我们的路由设计,Mongoose来与Mongodb数据库连接交互,使用Postman对我们设计的Api进行调试,快动起手来吧!

API设计中的token的思路

在API设计中,TOKEN用来判断用户是否有权限访问API.TOKEN首先不需要编解码处理. 一般TOKEN都是一些用户名+时间等内容的MD5的不可逆加密.然后通过一个USER_TOKEN表来判断用户请求中包含的TOKEN与USER_TOKEN表中的TOKEN是否一致即可.

具体实践过程主要为:

  1. 设定一个密钥比如key = ‘2323dsfadfewrasa3434'。
  2. 这个key 只有发送方和接收方知道。
  3. 调用时,发送方,组合各个参数用密钥 key按照一定的规则(各种排序,MD5,ip等)生成一个access_key。一起post提交到API接口。
  4. 接收方拿到post过来的参数以及这个access_key。也和发送一样,用密钥key 对各个参数进行一样的规则(各种排序,MD5,ip等)也生成一个access_key2。
  5. 对比 access_key 和 access_key2 。一样。则允许操作,不一样,报错返回或者加入黑名单。

token设计具体实践

废话不多说,先进入看我们的干货,这次选用Node.js+experss配合Mongoose来进入REST的token实践

项目地址: GitHub地址

git clone https://github.com/Nicksapp/nAuth-restful-api.git

新建项目

先看看我们的项目文件夹

- routes/
---- index.js
---- users.js
- models/
---- user.js
- config.js
- package.json
- passport.js
- index.js

npm init创建我们的package.json

接着在项目根文件夹下安装我们所需的依赖

npm install express body-parser morgan mongoose jsonwebtoken bcrypt passport passport-http-bearer --save 

  • express: 我们的主要开发框架
  • mongoose: 用来与MongoDB数据库进行交互的框架,请提前安装好MongoDB在PC上
  • morgan: 会将程序请求过程的信息显示在Terminal中,以便于我们调试代码
  • jsonwebtoken: 用来生成我们的token
  • passport: 非常流行的权限验证库
  • bcrypt: 对用户密码进行hash加密

-- save会将我们安装的库文件写入package.json的依赖中,以便其他人打开项目是能够正确安装所需依赖.

用户模型

定义我们所需用户模型,用于moogoose,新建models/user.js

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);

配置文件

./config.js 用来配置我们的MongoDB数据库连接和token的密钥。

module.exports = {
  'secret': 'learnRestApiwithNickjs', // used when we create and verify JSON Web Tokens
  'database': 'mongodb://localhost:27017/test' // 填写本地自己 mongodb 连接地址,xxx为数据表名
};

本地服务器配置

./index.js 服务器配置文件,也是程序的入口。

这里我们主要用来包含我们程序需要加载的库文件,调用初始化程序所需要的依赖。

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);
})

路由配置

./routes 主要存放路由相关文件

./routes/index.js 路由总入口,引入所使用路由

module.exports = (app) => {
  app.get('/', (req, res) => {
    res.json({ message: 'hello index!'});
  });

  app.use('/api', require('./users')); // 在所有users路由前加/api
};

./routes/users.js

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 // token 过期销毁时间设置
          });
          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;

passport配置

./passport.js 配置权限模块所需功能

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);
            });
        }
    ));
};

主要验证发送的token值与用户服务器端token值是否匹配,进行信息验证。

具体调试

现在就可以运行我们的代码看具体运作过程了!为了便于调试与参数的收发,我们使用postman(可在Chrome上或Mac上安装)来操作.

node index运行我们的本地服务器,访问 localhost:8080/ 应该就可以看到我们所返回的初始json值了,然我们继续深入测试。

POST访问localhost:8080/api/signup,我们来注册一个新用户,注意要设置bodyContent-Typex-www-form-urlencoded 以便我们的body-parser能够正确解析,好的我们成功模拟创建了我们的新用户。

连接一下数据库看下我们的用户信息是否也被正确存储(注:我使用的是MongoChef,十分强大MongoDB数据库管理软件),我们可以看到,我的password也被正确加密保存了。

接着POST访问localhost:8080/api/user/accesstoken,来为我的用户获得专属token,POST过程与注册相关,可以看到也正确生成我们的token值。

再看下我们的数据库中的用户信息,token值也被存入了进来,便于我们之后进行权限验证。

GET访问localhost:8080/api/user/user_info,同时将我们的token值在Header中以 Authorization: token 传入,正确获得用户名则表示我们访问请求通过了验证。

如果token值不正确,则返回HTTP状态码 401 Unauthorized 并拒绝访问请求。到这里我们的权限验证功能也就基本实现了。

总结

希望在看完这篇教程后能够对你在RESTful Api开发上有所启发,小生才疏学浅,过程中有什么不足的地方也欢迎指正。

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].