使用护照和passport.authenticate在路线申报后

时间:2017-09-06 08:48:06

标签: node.js passport.js koa2

我正在处理的应用程序要求所有身份验证代码在路由声明之后放置,而不是通过中间件将路由分成公共和私有路由,并在回调内部调用passport.authenticate进行登录方法(代码A),我需要在配置护照之前加载所有路由(代码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和GET而不是表单。

POST localhost:3000 / login?username = test& password = test

获取localhost:3000 / home

获取localhost:3000 / logout

0 个答案:

没有答案