我正在尝试将 Ember-Data 与 Express.JS 支持的 JSON-API 相关联。
我知道这些......
models
adapters
serializers
...但他们如何一起工作?它们如何适应 Ember.JS 的全貌?
如何在JSON-API和Ember.JS之间设置安全连接?
答案 0 :(得分:5)
这是一个非常广泛的问题,但最近经历了所有这些,我相信我可以提供详细的回复,说明我已经实施了。这很关键,因为有很多选项,如果您查看大部分教程,他们主要关注的是使用rails
作为后端,而不是node
或express.js
。我将使用express.js
基于您回答此问题。
我将在此前面加上记住,ember-data
是一个完全不同的ember分支,你可以绕过它,如果你觉得你的项目不需要它的功能而只是使用AJAX请求就完全不使用代替。 ember-data
为项目的初始启动增加了许多复杂性和开销。此外, TLS / SSL是您可以拥有的最重要的安全性,如果没有它,除此之外任何数量的尝试安全性都是无效的。现在已经开始了,让我们进入设置它的坚韧部分。
默认情况下,ember-data
使用基于JSON API specification的JSONAPIAdapter
。如果您使用默认Express.js
而没有Adapter
更改
Serializer
API服务器必须能够运行此规范
将项目分解为核心组件以及他们需要做什么,以及可用的选项如下(我用粗体做的):
express.js
ember-simple-auth
效果很好ember-simple-auth-token
为您提供了使用基于令牌的身份验证的预建授权程序基本流程如下:
以下是我如何设置
**设置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服务器以响应删除请求,验证错误等有很多复杂性。