成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Node.js+MongoDB對于RestfulApi中用戶token認證實踐

robin / 2576人閱讀

摘要:則是目前比較成熟的一套互聯(lián)網(wǎng)應用程序的設計理論。則允許操作,不一樣,報錯返回或者加入黑名單。再看下我們的數(shù)據(jù)庫中的用戶信息,值也被存入了進來,便于我們之后進行權限驗證。訪問同時將我們的值在中以傳入正確獲得用戶名則表示我們訪問請求通過了驗證。

關于安全性方面的建議

可以參考這篇總結(jié) 開發(fā)安全的 API 所需要核對的清單

安裝

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

運行

npm install

具體數(shù)據(jù)庫配置信息在config.js中設置

整體構(gòu)架

開發(fā)前先進行我們設計的構(gòu)想

路由設計

POST /api/signup: 用戶注冊

POST /api/user/accesstoken: 賬號驗證,獲取token

GET /api/users/info: 獲得用戶信息,需驗證

user 模型設計

name : 用戶名

password: 密碼

token: 驗證相關token

關于RESTful API

網(wǎng)上已經(jīng)有了很多關于RESTful的介紹,我這里也不過多重復了。想說的就是它的主要作用,就是對于現(xiàn)如今的網(wǎng)絡應用程序,分為前端和后端兩個部分,然而當前的發(fā)展趨勢就是應用平臺需求的擴大(IOS、Android、Webapp等等)

因此,就需要一種統(tǒng)一的機制,方便不同的應用平臺的前端設備與后端進行通信,也就是前后端的分離。這導致了API架構(gòu)的流行,甚至出現(xiàn)"API First"的設計思想。RESTful API則是目前比較成熟的一套互聯(lián)網(wǎng)應用程序的API設計理論。

技術棧

使用Node.js上的Express框架進行我們的路由設計,Mongoose來與Mongodb數(shù)據(jù)庫連接交互,使用Postman對我們設計的Api進行調(diào)試,快動起手來吧!

API設計中的token的思路

在API設計中,TOKEN用來判斷用戶是否有權限訪問API.TOKEN首先不需要編解碼處理. 一般TOKEN都是一些用戶名+時間等內(nèi)容的MD5的不可逆加密.然后通過一個USER_TOKEN表來判斷用戶請求中包含的TOKEN與USER_TOKEN表中的TOKEN是否一致即可.

具體實踐過程主要為:

設定一個密鑰比如key = ‘2323dsfadfewrasa3434"。

這個key 只有發(fā)送方和接收方知道。

調(diào)用時,發(fā)送方,組合各個參數(shù)用密鑰 key按照一定的規(guī)則(各種排序,MD5,ip等)生成一個access_key。一起post提交到API接口。

接收方拿到post過來的參數(shù)以及這個access_key。也和發(fā)送一樣,用密鑰key 對各個參數(shù)進行一樣的規(guī)則(各種排序,MD5,ip等)也生成一個access_key2。

對比 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創(chuàng)建我們的package.json

接著在項目根文件夾下安裝我們所需的依賴

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

express: 我們的主要開發(fā)框架

mongoose: 用來與MongoDB數(shù)據(jù)庫進行交互的框架,請?zhí)崆鞍惭b好MongoDB在PC上

morgan: 會將程序請求過程的信息顯示在Terminal中,以便于我們調(diào)試代碼

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數(shù)據(jù)庫連接和token的密鑰。

module.exports = {
  "secret": "learnRestApiwithNickjs", // used when we create and verify JSON Web Tokens
  "database": "mongodb://localhost:27017/test" // 填寫本地自己 mongodb 連接地址,xxx為數(shù)據(jù)表名
};
本地服務器配置

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

這里我們主要用來包含我們程序需要加載的庫文件,調(diào)用初始化程序所需要的依賴。

const express = require("express");
const app = express();
const bodyParser = require("body-parser");// 解析body字段模塊
const morgan = require("morgan"); // 命令行l(wèi)og顯示
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調(diào)試
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // 調(diào)用bodyParser模塊以便程序正確解析body傳入值

routes(app); // 路由引入

mongoose.Promise = global.Promise;
mongoose.connect(config.database); // 連接數(shù)據(jù)庫

app.listen(port, () => {
  console.log("listening on port : " + port);
})
路由配置

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

./routes/index.js 路由總?cè)肟?,引入所使用路?/p>

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({ // 在庫中創(chuàng)建一個新用戶
      name: req.body.name,
      password: req.body.password
    });
    // 保存用戶賬號
    newUser.save((err) => {
      if (err) {
        return res.json({success: false, message: "注冊失敗!"});
      }
      res.json({success: true, message: "成功創(chuàng)建新用戶!"});
    });
  }
});

// 檢查用戶名與密碼并生成一個accesstoken如果驗證通過
router.post("/user/accesstoken", (req, res) => {
  User.findOne({ // 根據(jù)用戶名查找是否存在該用戶
    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 發(fā)送 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);
            });
        }
    ));
};

主要驗證發(fā)送的token值與用戶服務器端token值是否匹配,進行信息驗證。

具體調(diào)試

現(xiàn)在就可以運行我們的代碼看具體運作過程了!為了便于調(diào)試與參數(shù)的收發(fā),我們使用postman(可在Chrome上或Mac上安裝)來操作.

node index運行我們的本地服務器,訪問 [localhost:8080/]()
應該就可以看到我們所返回的初始json值了,然我們繼續(xù)深入測試。

POST訪問[localhost:8080/api/signup](),我們來注冊一個新用戶,注意要設置bodyContent-Typex-www-form-urlencoded 以便我們的body-parser能夠正確解析,好的我們成功模擬創(chuàng)建了我們的新用戶。

連接一下數(shù)據(jù)庫看下我們的用戶信息是否也被正確存儲(注:我使用的是MongoChef,十分強大MongoDB數(shù)據(jù)庫管理軟件),我們可以看到,我的password也被正確加密保存了。

接著POST訪問[localhost:8080/api/user/accesstoken](),來為我的用戶獲得專屬token,POST過程與注冊相關,可以看到也正確生成我們的token值。

再看下我們的數(shù)據(jù)庫中的用戶信息,token值也被存入了進來,便于我們之后進行權限驗證。

GET訪問[localhost:8080/api/user/user_info](),同時將我們的token值在Header中以 Authorization: token 傳入,正確獲得用戶名則表示我們訪問請求通過了驗證。

如果token值不正確,則返回HTTP狀態(tài)碼 401 Unauthorized 并拒絕訪問請求。到這里我們的權限驗證功能也就基本實現(xiàn)了。

總結(jié)

希望在看完這篇教程后能夠?qū)δ阍赗ESTful Api開發(fā)上有所啟發(fā),小生才疏學淺,過程中有什么不足的地方也歡迎指正。

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86863.html

相關文章

  • Node.js+MongoDB對于RestfulApi用戶token認證實踐

    摘要:則是目前比較成熟的一套互聯(lián)網(wǎng)應用程序的設計理論。則允許操作,不一樣,報錯返回或者加入黑名單。再看下我們的數(shù)據(jù)庫中的用戶信息,值也被存入了進來,便于我們之后進行權限驗證。訪問同時將我們的值在中以傳入正確獲得用戶名則表示我們訪問請求通過了驗證。 showImg(https://segmentfault.com/img/remote/1460000008629635?w=800&h=534)...

    klinson 評論0 收藏0
  • node技術棧 - 收藏集 - 掘金

    摘要:異步最佳實踐避免回調(diào)地獄前端掘金本文涵蓋了處理異步操作的一些工具和技術和異步函數(shù)。 Nodejs 連接各種數(shù)據(jù)庫集合例子 - 后端 - 掘金Cassandra Module: cassandra-driver Installation ... 編寫 Node.js Rest API 的 10 個最佳實踐 - 前端 - 掘金全文共 6953 字,讀完需 8 分鐘,速讀需 2 分鐘。翻譯自...

    王偉廷 評論0 收藏0
  • 2018最新后端開發(fā)人員的路線圖

    摘要:簡評之前,后端開發(fā)路線圖僅僅是一個技術推薦,且沒有明確的方向指明應該遵循的順序,這份重新制作的指南將會給你一個更好的方向?,F(xiàn)在開始創(chuàng)建一個包并分發(fā)給其他人使用,并確保遵循迄今為止學到的標準和最佳實踐。 簡評:之前,后端開發(fā)路線圖僅僅是一個技術推薦,且沒有明確的方向指明應該遵循的順序,這份重新制作的指南將會給你一個更好的方向。 現(xiàn)在的 Web 開發(fā)與幾年前完全不同了,有很多不同的東西可以...

    王陸寬 評論0 收藏0
  • 架構(gòu)~微服務

    摘要:接下來繼續(xù)介紹三種架構(gòu)模式,分別是查詢分離模式微服務模式多級緩存模式。分布式應用程序可以基于實現(xiàn)諸如數(shù)據(jù)發(fā)布訂閱負載均衡命名服務分布式協(xié)調(diào)通知集群管理選舉分布式鎖和分布式隊列等功能。 SpringCloud 分布式配置 SpringCloud 分布式配置 史上最簡單的 SpringCloud 教程 | 第九篇: 服務鏈路追蹤 (Spring Cloud Sleuth) 史上最簡單的 S...

    xinhaip 評論0 收藏0
  • 聊聊畢業(yè)設計系列 --- 系統(tǒng)實現(xiàn)

    摘要:七牛云接入本系統(tǒng)的圖片,音視頻是放在七牛云,所以需要接入七牛云。在服務端通過接口請求來獲取七牛云上傳,客戶端獲取到七牛云,通過不同方案將帶上。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    null1145 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<