Skip to content

Commit e40af86

Browse files
committed
Merge branch 'v2.x'
# Conflicts: # CHANGELOG.md # README.md # lib/index.js # package.json
2 parents 761ba2c + ed59177 commit e40af86

File tree

8 files changed

+327
-249
lines changed

8 files changed

+327
-249
lines changed

CHANGELOG.md

+32
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
# Changelog
22

3+
## upcoming 3.0
4+
5+
- remove `ctx.passport` and save state variables (like `_passport` and `user`) in `ctx.state` instead
6+
- prevent `passport` from monkey patching `http.IncomingMessage`
7+
- change arguments from custom authentication callbacks from `user, info, status` to `err, user, info, status` (`err` added) to be consistent with passport
8+
9+
## 2.2.2
10+
11+
- remove `ctx.req.user` deprecation warning for now #66
12+
13+
## 2.2.1
14+
15+
- fix middleware to properly catch promise errors #63
16+
17+
## 2.2.0
18+
19+
- move `user` into `ctx.state`
20+
- user in `ctx.req.user` is deprecated and will removed eventually
21+
22+
## 2.1.0
23+
24+
- export KoaPassport as an alternative to the by default exported singleton
25+
26+
## 2.0.1
27+
28+
- use strict
29+
30+
## 2.0.0
31+
32+
- use promises rather than generators for `[email protected]` compatibility
33+
- use some es6 features
34+
335
## 1.3.0
436

537
- export KoaPassport as an alternative to the by default exported singleton

README.md

+24-5
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,46 @@
99
koa-passport version | koa version | branch | npm tag
1010
--------------------- | ------------| ------ | -------
1111
1.x | 1.x | master | latest
12-
2.x | 2.x | v2.x | next
12+
2.x, 3.x | 2.x | v2.x | next
13+
14+
## Migration to v`3.0.0-rc.1`
15+
16+
- change `ctx.passport.*` to `ctx.state.*` (e.g. `ctx.passport.user` to `ctx.state.user`)
17+
- don't call passport methods on `ctx.req` (e.g. use `ctx.login` instead of `ctx.req.login`)
18+
- update custom authentication callback arguments to `err, user, info, status` (e.g. `passport.authenticate('local', function(err, user, info, status) { ... })(ctx, next)`)
1319

1420
## Usage
1521

1622
```js
1723
// body parser
18-
var bodyParser = require('koa-bodyparser')
24+
const bodyParser = require('koa-bodyparser')
1925
app.use(bodyParser())
2026

2127
// Sessions
22-
var session = require('koa-session')
28+
const convert = require('koa-convert') // necessary until koa-generic-session has been updated to support koa@2
29+
const session = require('koa-generic-session')
2330
app.keys = ['secret']
24-
app.use(session(app))
31+
app.use(convert(session()))
2532

26-
var passport = require('koa-passport')
33+
const passport = require('koa-passport')
2734
app.use(passport.initialize())
2835
app.use(passport.session())
2936
```
3037

3138
[Example Application](https://github.com/rkusa/koa-passport-example)
3239

40+
Passport's values and methods are exposed as follows:
41+
42+
```js
43+
app.use(async ctx => {
44+
ctx.isAuthenticated()
45+
ctx.isUnauthenticated()
46+
ctx.login()
47+
ctx.logout()
48+
ctx.state.user
49+
})
50+
```
51+
3352
## License
3453

3554
[MIT](LICENSE)

lib/framework/koa.js

+69-62
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
'use strict'
2+
13
/**
24
* Module dependencies.
35
*/
4-
var passport = require('passport')
5-
var co = require('co')
6+
const passport = require('passport')
67

78
/**
89
* Passport's default/connect middleware.
910
*/
10-
var _initialize = require('passport/lib/middleware/initialize')
11-
var _authenticate = require('passport/lib/middleware/authenticate')
11+
const _initialize = require('passport/lib/middleware/initialize')
12+
const _authenticate = require('passport/lib/middleware/authenticate')
13+
const createReqMock = require('./request').create
1214

1315
/**
1416
* Passport's initialization middleware for Koa.
@@ -17,42 +19,46 @@ var _authenticate = require('passport/lib/middleware/authenticate')
1719
* @api private
1820
*/
1921
function initialize(passport) {
20-
var middleware = _initialize(passport)
21-
return function* passportInitialize(next) {
22-
var ctx = this
23-
22+
const middleware = promisify(_initialize(passport))
23+
return function passportInitialize(ctx, next) {
2424
// koa <-> connect compatibility:
25-
this.passport = {}
26-
var userProperty = passport._userProperty || 'user'
25+
const userProperty = passport._userProperty || 'user'
2726
// check ctx.req has the userProperty
2827
if (!ctx.req.hasOwnProperty(userProperty)) {
2928
Object.defineProperty(ctx.req, userProperty, {
3029
enumerable: true,
3130
get: function() {
32-
return ctx.passport[userProperty]
31+
return ctx.state[userProperty]
3332
},
3433
set: function(val) {
35-
ctx.passport[userProperty] = val
34+
ctx.state[userProperty] = val
3635
}
3736
})
3837
}
3938

40-
var req = createReqMock(ctx)
39+
// create mock object for express' req object
40+
const req = createReqMock(ctx)
4141

42-
// add aliases for passport's request extensions to Koa's context
43-
var login = ctx.req.login
44-
var logout = ctx.req.logout
4542

43+
// add Promise-based login method
44+
const login = req.login
4645
ctx.login = ctx.logIn = function(user, options) {
47-
return login.bind(req, user, options)
46+
return new Promise((resolve, reject) => {
47+
login.call(req, user, options, err => {
48+
if (err) reject(err)
49+
else resolve()
50+
})
51+
})
4852
}
49-
ctx.req.login = ctx.req.logIn = login.bind(req)
50-
ctx.logout = ctx.logOut = ctx.req.logout = ctx.req.logOut = logout.bind(req)
51-
ctx.isAuthenticated = ctx.req.isAuthenticated = ctx.req.isAuthenticated.bind(req)
52-
ctx.isUnauthenticated = ctx.req.isUnauthenticated = ctx.req.isUnauthenticated.bind(req)
5353

54-
yield middleware.bind(middleware, req, ctx)
55-
yield next
54+
// add aliases for passport's request extensions to Koa's context
55+
ctx.logout = ctx.logOut = req.logout.bind(req)
56+
ctx.isAuthenticated = req.isAuthenticated.bind(req)
57+
ctx.isUnauthenticated = req.isUnauthenticated.bind(req)
58+
59+
return middleware(req, ctx).then(function() {
60+
return next()
61+
})
5662
}
5763
}
5864

@@ -74,47 +80,40 @@ function authenticate(passport, name, options, callback) {
7480
options = options || {}
7581

7682
if (callback) {
77-
if (callback.constructor.name !== 'GeneratorFunction') {
78-
throw TypeError('Your custom authentication callback must be a Generator Function')
79-
}
80-
8183
// When the callback is set, neither `next`, `res.redirect` or `res.end`
8284
// are called. That is, a workaround to catch the `callback` is required.
8385
// The `passportAuthenticate()` method below will therefore set
84-
// `callback.done`. Then, once the authentication finishes, the modified
85-
// callback yields the original one and afterwards triggers `callback.done`
86-
// to inform `passportAuthenticate()` that we are ready.
87-
var _callback = callback
88-
callback = co.wrap(function*(err, user, info, status) {
89-
try {
90-
yield _callback(err, user, info, status)
91-
callback.done(null, false)
92-
} catch (err) {
93-
callback.done(err);
94-
}
95-
})
86+
// `callback.resolve` and `callback.reject`. Then, once the authentication
87+
// finishes, the modified callback calls the original one and afterwards
88+
// triggers either `callback.resolve` or `callback.reject` to inform
89+
// `passportAuthenticate()` that we are ready.
90+
const _callback = callback
91+
callback = function(err, user, info, status) {
92+
Promise.resolve(_callback(err, user, info, status))
93+
.then(() => callback.resolve(false))
94+
.catch(err => callback.reject(err))
95+
}
9696
}
9797

98-
var middleware = _authenticate(passport, name, options, callback)
99-
return function* passportAuthenticate(next) {
100-
var ctx = this
98+
const middleware = promisify(_authenticate(passport, name, options, callback))
10199

100+
return function passportAuthenticate(ctx, next) {
102101
// this functions wraps the connect middleware
103102
// to catch `next`, `res.redirect` and `res.end` calls
104-
var cont = yield function(done) {
103+
const p = new Promise((resolve, reject) => {
105104
// mock the `req` object
106-
var req = createReqMock(ctx)
105+
const req = createReqMock(ctx)
107106

108107
// mock the `res` object
109-
var res = {
108+
const res = {
110109
redirect: function(url) {
111110
ctx.redirect(url)
112-
done(null, false)
111+
resolve(false)
113112
},
114113
setHeader: ctx.set.bind(ctx),
115114
end: function(content) {
116115
if (content) ctx.body = content
117-
done(null, false)
116+
resolve(false)
118117
},
119118
set statusCode(status) {
120119
ctx.status = status
@@ -124,19 +123,23 @@ function authenticate(passport, name, options, callback) {
124123
}
125124
}
126125

126+
// update the custom callback above
127127
if (callback) {
128-
callback.done = done
128+
callback.resolve = resolve
129+
callback.reject = reject
129130
}
130131

131132
// call the connect middleware
132-
middleware(req, res, done)
133-
}
133+
middleware(req, res).then(resolve, reject)
134+
})
134135

135-
// cont equals `false` when `res.redirect` or `res.end` got called
136-
// in this case, yield next to continue through Koa's middleware stack
137-
if (cont !== false) {
138-
yield next
139-
}
136+
return p.then(cont => {
137+
// cont equals `false` when `res.redirect` or `res.end` got called
138+
// in this case, call next to continue through Koa's middleware stack
139+
if (cont !== false) {
140+
return next()
141+
}
142+
})
140143
}
141144
}
142145

@@ -169,15 +172,19 @@ function authorize(passport, name, options, callback) {
169172
*/
170173
module.exports = function() {
171174
return {
172-
initialize: initialize,
175+
initialize: initialize,
173176
authenticate: authenticate,
174-
authorize: authorize
177+
authorize: authorize
175178
}
176179
}
177180

178-
// create request mock
179-
var properties = require('./request')
180-
function createReqMock(ctx) {
181-
var req = Object.create(ctx.request, properties)
182-
return req
181+
function promisify(expressMiddleware) {
182+
return function(req, res) {
183+
return new Promise(function(resolve, reject) {
184+
expressMiddleware(req, res, function(err, result) {
185+
if (err) reject(err)
186+
else resolve(result)
187+
})
188+
})
189+
}
183190
}

lib/framework/request.js

+26-14
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,14 @@
2525
// Until this is fixed, koa-passport tries to properly delegate every possible
2626
// used property/method.
2727

28+
'use strict'
29+
2830
// Property/Method names to be delegated
29-
var keys = [
31+
let keys = [
3032
// passport
3133
'_passport',
3234
'user',
3335
'account',
34-
'login',
35-
'logIn',
36-
'logout',
37-
'logOut',
38-
'isAuthenticated',
39-
'isUnauthenticated',
4036
'authInfo',
4137

4238
// http.IncomingMessage
@@ -70,13 +66,13 @@ keys = keys.filter(function(key, i, self) {
7066
})
7167

7268
// create a delegate for each key
73-
var properties = module.exports = {
69+
const properties = {
7470
// mock express' .get('trust proxy')
7571
app: {
7672
// getter returning a mock for `req.app` containing
7773
// the `.get()` method
7874
get: function() {
79-
var ctx = this.ctx
75+
const ctx = this.ctx
8076
return {
8177
get: function(key) {
8278
if (key === 'trust proxy') {
@@ -93,7 +89,7 @@ var properties = module.exports = {
9389
keys.forEach(function(key) {
9490
properties[key] = {
9591
get: function() {
96-
var obj = getObject(this.ctx, key)
92+
const obj = getObject(this.ctx, key)
9793
if (!obj) return undefined
9894

9995
// if its a function, call with the proper context
@@ -107,17 +103,17 @@ keys.forEach(function(key) {
107103
return obj[key]
108104
},
109105
set: function(value) {
110-
var obj = getObject(this.ctx, key) || this.ctx.passport
106+
const obj = getObject(this.ctx, key) || this.ctx.state
111107
obj[key] = value
112108
}
113109
}
114110
})
115111

116-
// test where the key is available, either in `ctx.passport`, Node's request,
112+
// test where the key is available, either in `ctx.state`, Node's request,
117113
// Koa's request or Koa's context
118114
function getObject(ctx, key) {
119-
if (ctx.passport && (key in ctx.passport)) {
120-
return ctx.passport
115+
if (ctx.state && (key in ctx.state)) {
116+
return ctx.state
121117
}
122118

123119
if (key in ctx.request) {
@@ -134,3 +130,19 @@ function getObject(ctx, key) {
134130

135131
return undefined
136132
}
133+
134+
const IncomingMessageExt = require('passport/lib/http/request')
135+
136+
exports.create = function(ctx) {
137+
const req = Object.create(ctx.request, properties)
138+
139+
// add passport http.IncomingMessage extensions
140+
req.login = IncomingMessageExt.logIn
141+
req.logIn = IncomingMessageExt.logIn
142+
req.logout = IncomingMessageExt.logOut
143+
req.logOut = IncomingMessageExt.logOut
144+
req.isAuthenticated = IncomingMessageExt.isAuthenticated
145+
req.isUnauthenticated = IncomingMessageExt.isUnauthenticated
146+
147+
return req
148+
}

0 commit comments

Comments
 (0)