我正在处理的应用程序要求将所有身份验证代码放在路由声明之后,即我需要加载配置护照之前的所有路线(代码 B)。
我修改了这个例子:https ://github.com/rkusa/koa-passport-example 来帮助解释我想要完成的事情。上面的auth.js的精简版本如下:
const passport = require('koa-passport')
const fetchUser = (() => {
// This is an example! Use password hashing in your
const user = { id: 1, username: 'test', password: 'test' }
return async function() {
return user
}
})()
passport.serializeUser(function(user, done) {
console.log("serializing")
done(null, user.id)
})
passport.deserializeUser(async function(id, done) {
console.log("DEserializing")
try {
const user = await fetchUser()
done(null, user)
} catch(err) {
done(err)
}
})
const LocalStrategy = require('passport-local').Strategy
passport.use(new LocalStrategy(function(username, password, done) {
console.log("asked for authentication")
fetchUser()
.then(user => {
if (username === user.username && password === user.password) {
done(null, user)
} else {
done(null, false)
}
})
.catch(err => done(err))
}))
通过拆分公共和私有路由工作的server.js (代码 A)的剥离版本如下:
const Koa = require('koa')
const app = new Koa()
// trust proxy
app.proxy = true
// sessions
const session = require('koa-session')
app.keys = ['your-session-secret']
app.use(session({}, app))
// body parser
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
// authentication
require('./auth')
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session())
// routes
const fs = require('fs')
const route = require('koa-route')
//public routes
app.use(route.get('/login', (ctx) => {
ctx.body = "LOGIN";
}));
app.use(route.post('/login',
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login'
})
))
app.use(route.get('/logout', function(ctx) {
ctx.logout()
ctx.redirect('/login')
}))
// Require authentication for now
app.use(function(ctx, next) {
if (ctx.isAuthenticated()) {
console.log("authenticated user")
return next()
} else {
console.log("unauthenticated user")
ctx.redirect('/login')
}
})
//private route
app.use(route.get('/home', function(ctx) {
ctx.body = "home"
}))
// start server
const port = process.env.PORT || 3000
app.listen(port, () => console.log('Server listening on', port))
需要的是上面的功能,但是路由都是在认证之前声明的,然后我们稍后捕获认证请求。我写了一个替代的server.js(代码 B)试图做到这一点:
const Koa = require('koa')
const app = new Koa()
// trust proxy
app.proxy = true
// sessions
const session = require('koa-session')
app.keys = ['your-session-secret']
app.use(session({}, app))
// body parser
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
// routes
const fs = require('fs')
const route = require('koa-route')
app.use(route.get('/login', (ctx) => {
ctx.body = "LOGIN";
}));
app.use(route.post('/login', async (ctx, next) => {
ctx.id = 0;
console.log(); console.log("login");
await next();
}))
app.use(route.get('/home', async (ctx, next) => {
ctx.id = 1;
console.log(); console.log("home")
await next();
ctx.body = "home";
}))
app.use(route.get('/logout', async (ctx) => {
ctx.logout();
ctx.redirect('/login')
}))
const port = process.env.PORT || 3000
app.listen(port, () => console.log('Server listening on', port))
// authentication
require('./auth')
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session());
auth = async (ctx, next) => {
console.log("Check for authentication request")
if (ctx.id === 0 && !ctx.isAuthenticated()) {
//here I want to actually authenticate if request if for authentication. Previously this code would have been in the callback of the public route i.e. the post method for login
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login'
});
} else {
//middleware blocking access to other middlewares. Previously this would have been placed inside a non -async function and placed before all protected routes
if (ctx.isAuthenticated()) {
console.log("authenticated user")
return next()
} else {
console.log("unauthenticated user")
ctx.redirect('/login')
}
}
}
app.use(auth)
//app.use(MW1)
//app.use(MW2)
在每个路由回调中,我向 ctx 添加一个 id 属性,其中 ctx.id = 0 表示请求是身份验证发布请求。问题:passport.authenticate 没有被调用。
然后我添加一个中间件来检查请求的其余部分是否经过身份验证(与代码 A 相同)。这部分有效,即我的私有路由 /home 重定向到 /login 因为用户未通过身份验证。
我遇到的另一个问题是发送注销请求时出现错误“ctx.logout 不是函数”。我想这与 passport.authenticate 根本没有被调用的事实有关。
我正在使用 Postman 发送 POST 和 GETs 而不是表单。
POST localhost:3000/login?username=test&password=test
获取本地主机:3000/家
获取本地主机:3000/注销