2

我正在处理的应用程序要求将所有身份验证代码放在路由声明之后,即我需要加载配置护照之前的所有路线(代码 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/注销

4

0 回答 0