Update session / token documentation
This commit is contained in:
parent
64d8ff986b
commit
1bb95607b9
48
docs/api.md
48
docs/api.md
|
@ -211,6 +211,46 @@ app.use(loopback.rest());
|
|||
View generated REST documentation by visiting: [http://localhost:3000/_docs](http://localhost:3000/_docs).
|
||||
|
||||
|
||||
### Middleware
|
||||
|
||||
LoopBack comes bundled with several `connect` / `express` style middleware.
|
||||
|
||||
#### loopback.token(options)
|
||||
|
||||
**Options**
|
||||
|
||||
- `cookies` - An `Array` of cookie names
|
||||
- `headers` - An `Array` of header names
|
||||
- `params` - An `Array` of param names
|
||||
|
||||
Each array is used to add additional keys to find an `accessToken` for a `request`.
|
||||
|
||||
The following example illustrates how to check for an `accessToken` in a custom cookie, query string parameter
|
||||
and header called `foo-auth`.
|
||||
|
||||
```js
|
||||
app.use(loopback.token({
|
||||
cookies: ['foo-auth'],
|
||||
headers: ['foo-auth', 'X-Foo-Auth'],
|
||||
cookies: ['foo-auth', 'foo_auth']
|
||||
}));
|
||||
```
|
||||
|
||||
**Defaults**
|
||||
|
||||
By default the following names will be checked. These names are appended to any optional names. They will always
|
||||
be checked, but any names specified will be checked first.
|
||||
|
||||
```js
|
||||
params.push('access_token');
|
||||
headers.push('X-Access-Token');
|
||||
headers.push('authorization');
|
||||
cookies.push('access_token');
|
||||
cookies.push('authorization');
|
||||
```
|
||||
|
||||
> **NOTE:** The `loopback.token()` middleware will only check for [signed cookies](http://expressjs.com/api.html#req.signedCookies).
|
||||
|
||||
### Model
|
||||
|
||||
A Loopback `Model` is a vanilla JavaScript class constructor with an attached set of properties and options. A `Model` instance is created by passing a data object containing properties to the `Model` constructor. A `Model` constructor will clean the object passed to it and only set the values matching the properties you define.
|
||||
|
@ -565,8 +605,8 @@ User.login = function (username, password, fn) {
|
|||
} else if(!user) {
|
||||
fn(failErr);
|
||||
} else if(user.password === passwordHash) {
|
||||
MySessionModel.create({userId: user.id}, function (err, session) {
|
||||
fn(null, session.id);
|
||||
MyAccessTokenModel.create({userId: user.id}, function (err, accessToken) {
|
||||
fn(null, accessToken.id);
|
||||
});
|
||||
} else {
|
||||
fn(failErr);
|
||||
|
@ -585,7 +625,7 @@ loopback.remoteMethod(
|
|||
{arg: 'username', type: 'string', required: true},
|
||||
{arg: 'password', type: 'string', required: true}
|
||||
],
|
||||
returns: {arg: 'sessionId', type: 'any'},
|
||||
returns: {arg: 'accessTokenId', type: 'any'},
|
||||
http: {path: '/sign-in'}
|
||||
}
|
||||
);
|
||||
|
@ -637,7 +677,7 @@ Define an instance method.
|
|||
|
||||
```js
|
||||
User.prototype.logout = function (fn) {
|
||||
MySessionModel.destroyAll({userId: this.id}, fn);
|
||||
MyAccessTokenModel.destroyAll({userId: this.id}, fn);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -25,16 +25,16 @@ var User = loopback.User.extend('user');
|
|||
// attach to the memory connector
|
||||
User.attachTo(memory);
|
||||
|
||||
// also attach the session model to a data source
|
||||
User.session.attachTo(memory);
|
||||
// also attach the accessToken model to a data source
|
||||
User.accessToken.attachTo(memory);
|
||||
|
||||
// expose over the app's api
|
||||
app.model(User);
|
||||
```
|
||||
|
||||
**Note:** By default the `loopback.User` model uses the `loopback.Session` model to persist sessions. You can change this by setting the `session` property.
|
||||
**Note:** By default the `loopback.User` model uses the `loopback.AccessToken` model to persist access tokens. You can change this by setting the `accessToken` property.
|
||||
|
||||
**Note:** You must attach both the `User` and `User.session` model's to a data source!
|
||||
**Note:** You must attach both the `User` and `User.accessToken` model's to a data source!
|
||||
|
||||
#### User Creation
|
||||
|
||||
|
@ -49,13 +49,13 @@ User.create({email: 'foo@bar.com', password: 'bar'}, function(err, user) {
|
|||
|
||||
#### Login a User
|
||||
|
||||
Create a session for a user using the local auth strategy.
|
||||
Create an `accessToken` for a user using the local auth strategy.
|
||||
|
||||
**Node.js**
|
||||
|
||||
```js
|
||||
User.login({username: 'foo', password: 'bar'}, function(err, session) {
|
||||
console.log(session);
|
||||
User.login({username: 'foo', password: 'bar'}, function(err, accessToken) {
|
||||
console.log(accessToken);
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -88,8 +88,8 @@ POST
|
|||
|
||||
```js
|
||||
// login a user and logout
|
||||
User.login({"email": "foo@bar.com", "password": "bar"}, function(err, session) {
|
||||
User.logout(session.id, function(err) {
|
||||
User.login({"email": "foo@bar.com", "password": "bar"}, function(err, accessToken) {
|
||||
User.logout(accessToken.id, function(err) {
|
||||
// user logged out
|
||||
});
|
||||
});
|
||||
|
@ -106,7 +106,7 @@ User.findOne({email: 'foo@bar.com'}, function(err, user) {
|
|||
POST /users/logout
|
||||
...
|
||||
{
|
||||
"sid": "<session id from user login>"
|
||||
"sid": "<accessToken id from user login>"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -175,23 +175,23 @@ User.confirmReset(token, function(err) {
|
|||
});
|
||||
```
|
||||
|
||||
### Session Model
|
||||
### AccessToken Model
|
||||
|
||||
Identify users by creating sessions when they connect to your loopback app. By default the `loopback.User` model uses the `loopback.Session` model to persist sessions. You can change this by setting the `session` property.
|
||||
Identify users by creating accessTokens when they connect to your loopback app. By default the `loopback.User` model uses the `loopback.AccessToken` model to persist accessTokens. You can change this by setting the `accessToken` property.
|
||||
|
||||
```js
|
||||
// define a custom session model
|
||||
var MySession = loopback.Session.extend('my-session');
|
||||
// define a custom accessToken model
|
||||
var MyAccessToken = loopback.AccessToken.extend('MyAccessToken');
|
||||
|
||||
// define a custom User model
|
||||
var User = loopback.User.extend('user');
|
||||
|
||||
// use the custom session model
|
||||
User.session = MySession;
|
||||
// use the custom accessToken model
|
||||
User.accessToken = MyAccessToken;
|
||||
|
||||
// attach both Session and User to a data source
|
||||
// attach both AccessToken and User to a data source
|
||||
User.attachTo(loopback.memory());
|
||||
MySession.attachTo(loopback.memory());
|
||||
MyAccessToken.attachTo(loopback.memory());
|
||||
```
|
||||
|
||||
### Email Model
|
||||
|
|
|
@ -10,7 +10,7 @@ A LoopBack model consists of:
|
|||
Apps use the model API to display information to the user or trigger actions
|
||||
on the models to interact with backend systems. LoopBack supports both "dynamic" schema-less models and "static", schema-driven models.
|
||||
|
||||
_Dynamic models_ require only a name. The format of the data are specified completely and flexibly by the client application. Well-suited for data that originates on the client, dynamic models enable you to persist data both between sessions and between devices without involving a schema.
|
||||
_Dynamic models_ require only a name. The format of the data are specified completely and flexibly by the client application. Well-suited for data that originates on the client, dynamic models enable you to persist data both between accessTokens and between devices without involving a schema.
|
||||
|
||||
_Static models_ require more code up front, with the format of the data specified completely in JSON. Well-suited to both existing data and large, intricate datasets, static models provide structure and
|
||||
consistency to their data, preventing bugs that can result from unexpected data in the database.
|
||||
|
|
|
@ -11,9 +11,8 @@ var RemoteObjects = require('strong-remoting');
|
|||
|
||||
module.exports = token;
|
||||
|
||||
function token(app, options) {
|
||||
function token(options) {
|
||||
options = options || {};
|
||||
var tokenModelName = options.tokenModelName || 'AccessToken';
|
||||
var TokenModel = options.model;
|
||||
assert(TokenModel, 'loopback.token() middleware requires a AccessToken model');
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
var Model = require('../loopback').Model
|
||||
, loopback = require('../loopback')
|
||||
, crypto = require('crypto')
|
||||
, uid = require('uid2');
|
||||
, uid = require('uid2')
|
||||
, DEFAULT_TOKEN_LEN = 64;
|
||||
|
||||
/**
|
||||
* Default AccessToken properties.
|
||||
|
@ -30,11 +31,11 @@ var AccessToken = module.exports = Model.extend('AccessToken', properties);
|
|||
*/
|
||||
|
||||
AccessToken.createAccessTokenId = function (fn) {
|
||||
uid(this.settings.accessTokenIdLength || 64, function(err, buf) {
|
||||
uid(this.settings.accessTokenIdLength || DEFAULT_TOKEN_LEN, function(err, guid) {
|
||||
if(err) {
|
||||
fn(err);
|
||||
} else {
|
||||
fn(null, buf.toString('base64'));
|
||||
fn(null, guid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -98,16 +99,16 @@ function tokenIdForRequest(req, options) {
|
|||
}
|
||||
}
|
||||
|
||||
for(length = headers.length; i < length; i++) {
|
||||
id = req.header(params[i]);
|
||||
for(i = 0, length = headers.length; i < length; i++) {
|
||||
id = req.header(headers[i]);
|
||||
|
||||
if(typeof id === 'string') {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
for(length = headers.length; i < length; i++) {
|
||||
id = req.signedCookies(cookies[i]);
|
||||
for(i = 0, length = headers.length; i < length; i++) {
|
||||
id = req.signedCookies[cookies[i]];
|
||||
|
||||
if(typeof id === 'string') {
|
||||
return id;
|
||||
|
|
|
@ -4,30 +4,36 @@ var Token = loopback.AccessToken.extend('MyToken');
|
|||
// attach Token to testing memory ds
|
||||
Token.attachTo(loopback.memory());
|
||||
|
||||
describe('loopback.token(app, options)', function() {
|
||||
describe('loopback.token(options)', function() {
|
||||
beforeEach(createTestingToken);
|
||||
|
||||
it('should populate req.token from the query string', function (done) {
|
||||
var app = loopback();
|
||||
var options = {};
|
||||
options.model = Token;
|
||||
var testToken = this.token;
|
||||
app.use(loopback.token(app, options));
|
||||
app.get('/', function (req, res) {
|
||||
try {
|
||||
assert(req.accessToken, 'req should have accessToken');
|
||||
assert(req.accessToken.id === testToken.id);
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
res.send('ok');
|
||||
});
|
||||
|
||||
request(app)
|
||||
createTestAppAndRequest(this.token, done)
|
||||
.get('/?access_token=' + this.token.id)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should populate req.token from a header', function (done) {
|
||||
createTestAppAndRequest(this.token, done)
|
||||
.get('/')
|
||||
.set('authorization', this.token.id)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should populate req.token from a secure cookie', function (done) {
|
||||
var app = createTestApp(this.token, done);
|
||||
|
||||
request(app)
|
||||
.get('/token')
|
||||
.end(function(err, res) {
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', res.header['set-cookie'])
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createTestingToken(done) {
|
||||
|
@ -38,3 +44,30 @@ function createTestingToken(done) {
|
|||
done();
|
||||
});
|
||||
}
|
||||
|
||||
function createTestAppAndRequest(testToken, done) {
|
||||
var app = createTestApp(testToken, done);
|
||||
return request(app);
|
||||
}
|
||||
|
||||
function createTestApp(testToken, done) {
|
||||
var app = loopback();
|
||||
|
||||
app.use(loopback.cookieParser('secret'));
|
||||
app.use(loopback.token({model: Token}));
|
||||
app.get('/token', function(req, res) {
|
||||
res.cookie('authorization', testToken.id, {signed: true});
|
||||
res.end();
|
||||
});
|
||||
app.get('/', function (req, res) {
|
||||
try {
|
||||
assert(req.accessToken, 'req should have accessToken');
|
||||
assert(req.accessToken.id === testToken.id);
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
res.send('ok');
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue