Ember-Data使用JSON-API

时间:2016-11-16 18:56:10

标签: json express ember.js models

我正在尝试将 Ember-Data Express.JS 支持的 JSON-API 相关联。

我知道这些......

models adapters serializers

...但他们如何一起工作?它们如何适应 Ember.JS 的全貌?

如何在JSON-API和Ember.JS之间设置安全连接

1 个答案:

答案 0 :(得分:5)

这是一个非常广泛的问题,但最近经历了所有这些,我相信我可以提供详细的回复,说明我已经实施了。这很关键,因为有很多选项,如果您查看大部分教程,他们主要关注的是使用rails作为后端,而不是nodeexpress.js 。我将使用express.js基于您回答此问题。

我将在此前面加上记住,ember-data是一个完全不同的ember分支,你可以绕过它,如果你觉得你的项目不需要它的功能而只是使用AJAX请求就完全不使用代替。 ember-data为项目的初始启动增加了许多复杂性和开销。此外, TLS / SSL是您可以拥有的最重要的安全性,如果没有它,除此之外任何数量的尝试安全性都是无效的。现在已经开始了,让我们进入设置它的坚韧部分。

默认情况下,ember-data使用基于JSON API specificationJSONAPIAdapter。如果您使用默认Express.js而没有Adapter更改

,那么您的Serializer API服务器必须能够运行此规范

将项目分解为核心组件以及他们需要做什么,以及可用的选项如下(我用粗体做的):

  • Express.js API服务器
    • Express API路线
    • 身份验证库
      • Passport适用于express.js
      • 定制
    • 认证机制
      • 基于令牌
      • 基于Cookie
    • 数据建模
      • 蒙戈
      • Sequelize
      • 其他
  • Ember.js基于Web Server
    • 适配器(处理发送/接收数据和处理错误)
      • application.js:为整个应用程序配置适配器
    • Serializer(这涉及使适配器ember中的数据可用)
      • 默认不需要
    • 身份验证员(这个
      • ember-simple-auth效果很好
      • 建立自己的:example
    • 认证器
      • ember-simple-auth-token为您提供了使用基于令牌的身份验证的预建授权程序
  • 数据库
    • MongoDB(基于文档的非关系型数据库)
    • Redis(在内存非关系型数据库中)
    • MySQL (关系数据库)
    • PostGreSQL(关系数据库)
    • 其他

基本流程如下:

  • 用户尝试登录ember.js app
  • Ember.js使用身份验证器从API服务器请求访问
  • API服务器验证用户并在标题
  • 中返回JSON Web令牌
  • Ember.js使用授权程序并将JSON Web令牌添加到标头以供将来的API请求使用
  • 通过带有授权程序头的适配器
  • 从Ember向API服务器进行API调用
  • API服务器验证令牌并搜索所需的数据
  • API服务器使用JSON API规范格式的数据进行响应
  • Ember.js适配器接收数据并处理响应
  • Ember.js序列化程序从适配器接收数据并使其可由Ember
  • 使用
  • Ember数据从序列化程序接收模型数据并将其存储在缓存中
  • 模型数据基于Ember.js页面上的模板和控制器填充

以下是我如何设置

**设置Ember.js最多使用Express.js API服务器**

为ember-cli安装以下项目:

ember install ember-simple-auth - 用于身份验证
ember install ember-simple-auth-token - 用于基于令牌的身份验证

app/adapters/application.js中的

import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin'; // Authenticating data from the API server
import Ember from 'ember';
import ENV from '../config/environment';

export default DS.JSONAPIAdapter.extend(DataAdapterMixin,{

  authManager: Ember.inject.service('session'),

  host: ENV.apihost, // location of the API server
  namespace: ENV.apinamespace, // Namespace of API server ie: 'api/v1'
  authorizer: 'authorizer:token', // Authorizer to use for authentication

  ajax: function(url, method, hash) {
    hash = hash || {}; // hash may be undefined
    hash.crossDomain = true; // Needed for CORS
    return this._super(url, method, hash);
  }
});

config/environment.js

ENV.host = 'http://localhost:4000'; /* this assumes the express.js server
is running on port 4000 locally, in a production environment it would point
to https://domainname.com/ */
ENV['ember-simple-auth'] = {
   authorizer: 'authorizer:token', //uses ember-simple-auth-token authorizer
   crossOriginWhitelist: ['http://localhost:4000'], // for CORS
   baseURL: '/',
   authenticationRoute: 'login', // Ember.js route that does authentication
   routeAfterAuthentication: 'profile', // Ember.js route to transition to after authentication
   routeIfAlreadyAuthenticated: 'profile' // Ember.js route to transition to if already authenticated
 };

 ENV['ember-simple-auth-token'] = {
   serverTokenEndpoint: 'http://localhost:4000/auth/token', // Where to get JWT from
   identificationField: 'email', // identification field that is sent to Express.js server
   passwordField: 'password', // password field sent to Express.js server
   tokenPropertyName: 'token', // expected response key from Express.js server
   authorizationPrefix: 'Bearer ', // header value prefix
   authorizationHeaderName: 'Authorization', // header key
   headers: {},
 };
 ENV['apihost'] = "http://localhost:4000" // Host of the API server passed to `app/adapters/application.js`
 ENV['apinamespace'] = ""; // Namespace of API server passed to `app/adapters/application.js`

**设置Express.js服务器**

必需的包裹:

express:自我解释性 body-parser:用于解析ember.js站点的JSON cors:用于CORS支持
ejwt:在大多数路由上要求JWT到您的API服务器
passport:用于验证用户身份 passport-json:用于验证用户身份 bcrypt:用于散列/腌制用户密码
sequelize:用于数据建模

**设置server.js **

var express = require('express'); // App is built on express framework
var bodyParser = require('body-parser'); // For parsing JSON passed to use through the front end app
var cors = require('cors'); // For CORS support
var ejwt = require('express-jwt');
var passport = require('passport');
// Load Configuration files
var Config = require('./config/environment'),
     config = new Config // Load our Environment configuration based on NODE_ENV environmental variable. Default is test.
var corsOptions = {
  origin: config.cors
};    
var app = express(); // Define our app object using express
app.use(bodyParser.urlencoded({extended: true})); // use x-www-form-urlencoded used for processing submitted forms from the front end app
app.use(bodyParser.json()); // parse json bodies that come in from the front end app
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // THIS ALLOWS ACCEPTING EMBER DATA BECAUSE JSON API FORMAT
app.use(cors(corsOptions)); // Cross-Origin Resource Sharing support
app.use(passport.initialize()); // initialize passport
app.use(ejwt({ secret: config.secret}).unless({path: ['/auth/token',  { url : '/users', methods: ['POST']}]}));
require('./app/routes')(app); // Load our routes file that handles all the API call routing
app.listen(config.port); // Start our server on the configured port. Default is 4000
console.log('listening on port : ' + config.port);
config/passport.js

中的

// config/passport.js
// Configure Passport for local logins

// Required Modules
var JsonStrategy = require('passport-json').Strategy;

// 
var User = require('../app/models/users'); // load user model

// Function
module.exports = function (passport) {
// serialize the user for the session
passport.serializeUser(function (user, done) {
    done(null, user.id);
});

// deserialize the user
passport.deserializeUser(function (id, done) {
    User.findById(id).then(function (user) {
        done(null, user);
    });
});
// LOCAL LOGIN ==========================================================
passport.use('json', new JsonStrategy({
    usernameProp : 'email',
    passwordProp : 'password',
    passReqToCallback : true
},
function (req, email, password, done) {
    User.findOne({where : {'email' : email }}).then(function (user) { // check against email
        if (!user) {
          User.findOne({where : {'displayName' : email}}).then(function(user){ //check against displayName
          if (!user) return done(null, false);
          else if (User.validatePassword(password,user.password)) return done(null, user);
          else return done(null, false);
          });
        }
        else if (User.validatePassword(password,user.password)) return done(null, user);
        else return done(null, false);
    });
}));
};

示例app/models/users.js用户续集模型

// Load required Packages
var Sequelize = require('sequelize');
var bcrypt = require('bcrypt-node')
// Load required helpers
var sequelize = require('../helpers/sequelizeconnect');
var config =  new require('../../config/environment'); // Load our Environment  configuration based on NODE_ENV environmental variable. Default is test.

// Load other models

// Define model
var Users = sequelize.define('users', {
  "email": { type: Sequelize.STRING}, // user email
  "password": { type: Sequelize.STRING} // user password
});

// Methods =======================================================

// Hash a password before storing
Users.generateHash = function(password) {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};

// Compare a password from the DB
Users.validatePassword = function(password, dbpassword) {
  return bcrypt.compareSync(password, dbpassword);
}

module.exports = Users

此时,您的express.js服务器只需要routes.js设置您的API服务器所需的路由,至少/auth/token才能执行身份验证。 Ember.js JSON API适配器期望成功响应的示例是:

var jsonObject = { // create json response object
   "data": {
       "type": "users", // ember.js model
       "id": 1, // id of the model
       "attributes": {
           "email" : "example@example.com",
       }
   }
}
res.status(201).json(jsonObject); // send new data object with 201/OK as a response

设置JSON API服务器以响应删除请求,验证错误等有很多复杂性。