2016-05-17 31 views
12

TL; DR - Cách kiểm tra tài nguyên trong API nút (Express) sử dụng JWT cho xác thực bằng mã thông báo là gì được cấp cho tên người dùng/mật khẩu đăng nhập?Cách kiểm tra API nút sử dụng xác thực JWT (với thông tin đăng nhập người dùng để nhận mã thông báo)

Tôi rất mới để thử nghiệm và muốn nhận được một số lời khuyên. Mục tiêu cuối cùng là có một API được kiểm tra đầy đủ và sau đó bắt đầu tìm hiểu cách kết nối với giải pháp Tích hợp liên tục.

Technologies sử dụng

  • Tôi đã viết một API trong Node sử dụng nhanh.
  • Mongo là cơ sở dữ liệu.
  • Mongoose được sử dụng làm ODM.
  • jsonwebtoken gói được sử dụng để tạo/xác minh mã thông báo.
  • Hộ chiếu được sử dụng để dễ dàng thêm Xác thực người dùng làm phần mềm trung gian Express trên các tuyến đường.

Thông tin API

API có nguồn tài nguyên khác nhau - các chi tiết cụ thể trong số đó là không quan trọng đối với truy vấn này nhưng cho phép chỉ giả vờ đó là ứng dụng Todo phổ biến để đơn giản.

Mỗi tài nguyên riêng lẻ được lưu trong cơ sở dữ liệu được liên kết với một Người dùng.

API sử dụng JWT để xác thực trên các điểm cuối tài nguyên khác nhau. Bản thân mã thông báo chứa ID người dùng duy nhất được lưu trữ đối với tài nguyên trong cơ sở dữ liệu Mongo. Để nhận được mã thông báo, yêu cầu người dùng đăng ký lần đầu (trả về mã thông báo) và sau đó đăng nhập để nhận mã thông báo mới.

Mã giả mạo.

tôi sẽ đơn giản hóa mã dưới đây và không sử dụng bất kỳ configs môi trường, vv ...

app.js

var express = require('express'); 
var app = express(); 
var mongoose = require('mongoose'); 
var bodyParser = require('body-parser'); 
var passport = require('passport'); 

mongoose.connect('mongodb://localhost/somedatabasename'); 

app.set('port', process.env.PORT || 3000); 
app.use(bodyParser.urlencoded({ extended: true })); 
app.use(bodyParser.json()); 

app.use(passport.initialize()); 
// ... Passport JWT Strategy goes here - omitted for simplicity ... 

var userRouter = require('./api/users/routes'); 
app.use('/users', userRouter); 
var todoRouter = require('./api/todos/routes'); 
app.use('/todos', todoRouter); 

app.listen(app.get('port'), function() { 
    console.log('App now running on http://localhost:' + app.get('port')); 
}); 

./api/todos/routes.js

var router = require('express').Router(); 
var controller = require('./controller'); 
var passport = require('passport'); 

router.route('/') 
    .all(passport.authenticate('jwt', { session: false})) 
    .get(controller.getAll) 
    .post(controller.create); 

router.route('/:id') 
    .all(passport.authenticate('jwt', { session: false})) 
    .get(controller.getOne) 
    .put(controller.update) 
    .delete(controller.delete); 

module.exports = router; 

./api/users/routes.js

var router = require('express').Router(); 
var controller = require('./controller'); 
var passport = require('passport'); 

router.route('/') 
    // User signup 
    .post(controller.create); 

router.route('/me') 
    // User Login 
    .post(passport.authenticate('local', { session: false}), controller.login) 
    // Get current user's data 
    .get(passport.authenticate('jwt', { session: false}), controller.getOne) 
    // Update current user's data 
    .put(passport.authenticate('jwt', { session: false}), controller.update) 
    // Delete current user 
    .delete(passport.authenticate('jwt', { session: false}), controller.delete); 

module.exports = router; 

./api/users/model.js

var mongoose = require('mongoose'); 
var bcrypt = require('bcrypt'); 

var UserSchema = new mongoose.Schema({ 
    username: { 
    type: String, 
    required: true, 
    unique: true 
    }, 
    password: { 
    type: String, 
    required: true 
    } 
}); 

// ... for simplicity imagine methods here to 
// - hash passwords on a pre save hook using bcrypt 
// - compare passwords using bcrypt when logging in 

module.exports = mongoose.model('User', UserSchema); 

./api/todos/model.js

var mongoose = require('mongoose'); 
var Schema = mongoose.Schema; 

var momentSchema = new Schema({ 
    title: { 
    type: String 
    }, 

    // Bunch of other fields here... 

    _user: { 
    type: Schema.Types.ObjectId, 
    ref: 'User' 
    } 
}); 

module.exports = mongoose.model('Moment', momentSchema); 

tôi đã bỏ qua một số các mã ví dụ để giữ cho nó sạch sẽ và đơn giản.

Ví dụ, bộ điều khiển các của người sử dụng sẽ bao gồm các mô hình và chức năng của nó sẽ:

  • controller.create - đăng ký cho người dùng mới (lợi nhuận token)
  • controller.login - sau khi kết hợp tên người dùng/mật khẩu được xác nhận bởi Hộ chiếu địa phương, sau đó trả lại mã thông báo hợp lệ
  • controller.getOne - dựa trên Sử dụng ID r được lấy từ mã thông báo JWT, trả về dữ liệu của người dùng từ Mongo bằng Mongoose.
  • controller.update - Cập nhật dữ liệu của người dùng trong Mongo sử dụng Mongoose
  • controller.delete - Xóa dữ liệu người dùng trong Mongo sử dụng Mongoose

điều khiển Các Todo của sẽ làm điều gì đó tương tự - chỉ tương tác với dữ liệu Mongo thông qua Mongoose nhưng các truy vấn sẽ luôn bao gồm ID người dùng để liên kết mục Todo cụ thể (ví dụ) với Người dùng được xác thực (được xác thực qua JWT).

kiểm tra câu hỏi hóc búa

Làm thế nào tôi sẽ đi về thử nghiệm một cái gì đó như thế này sử dụng một sự kết hợp của Mocha, Chai và SuperTest?

Sẽ I:

  • tạo ra một cơ sở dữ liệu thử nghiệm trong vòng Mongo và có chuỗi kết nối khác nhau trong các bài kiểm tra? Điều này có nghĩa là tiết kiệm dữ liệu thực tế được lưu trữ trong cơ sở dữ liệu để thử nghiệm.
  • Giả lập dữ liệu bằng cách nào đó và không sử dụng cơ sở dữ liệu thử nghiệm? Nhưng sau đó, cách người dùng lưu/đăng nhập được xử lý để truy xuất mã thông báo?

Làm cách nào để thử nghiệm hoạt động cục bộ khi phát triển so với khi bạn triển khai bằng một số công cụ CI (điều mà tôi chưa từng học trong nghiên cứu)?

Bất kỳ trợ giúp sẽ được nhiều đánh giá cao và tôi hy vọng tôi đã đưa đủ thông tin với các dữ liệu giả/code trên:./

+0

Xin chào! Bạn đã tìm ra điều này chưa? Tôi cũng đang cố gắng thực hiện loại thử nghiệm này. –

Trả lời

1

Trong thử nghiệm, bạn sẽ thường chế nhạo Mongo bạn DB (cái gì đó như mongo-mock Bằng cách này, bạn không cần một cơ sở dữ liệu thực sự chạy để chạy thử nghiệm của bạn (bạn không thử nghiệm cơ sở dữ liệu, mà là mã của bạn)

Trong khi thử nghiệm, bạn sẽ thay thế mongodb bằng mongo-mock và sau đó chạy thử nghiệm của bạn. bạn sẽ cần phải đăng lên URL /me của mình với thông tin đăng nhập được giả mạo hợp lệ, điểm cuối đó sẽ trả về mã thông báo mà sau đó bạn sẽ sử dụng trên cuộc gọi tiếp theo của mình để kiểm tra điểm cuối khác của bạn.

Về mặt mã thông báo, tôi thường kiểm tra ở đầu yêu cầu trước khi nhập các điểm cuối khác.(Tôi chưa sử dụng hộ chiếu nhưng ý tưởng là):

app.use(validate_jwt_middleware); 
app.use('/users', userRouter); 

Bằng cách này, nếu mã thông báo không hợp lệ, nó không hợp lệ cho toàn bộ trang web, không chỉ phần của bạn.

Ngoài ra, tôi không sử dụng SuperTest, nhưng chai-http, vì vậy tôi không thể giúp bạn với các chi tiết cụ thể của bạn.

Hy vọng điều này sẽ giúp,

Các vấn đề liên quan