rkusa/koa-passport

passport.deserializeuser not called,and ctx.isAuthenticated() always equals false

cheneyweb opened this issue · 8 comments

  1. The following is my key package
    "koa": "^2.2.0",
    "koa-passport": "^3.0.0",
    "koa-router": "^7.0.1",
    "koa-session": "^5.0.0"

  2. My problem is when I use "ctx.isAuthenticated()" to check if user login before, ctx.isAuthenticated() always equal false even user has login by passport.authenticate

3.The following is my code:

app.js

const session = require('koa-session')
const passport = require(__dirname + '/src/auth/passport_config.js')
const xauth = require('./src/auth/router_auth.js')

const app = new Koa()
app.proxy = true
app.keys = ['your-session-secret']
app.use(session(app))

app.use(bodyParser())

app.use(passport.initialize())
app.use(passport.session())
app.use(mount('/',xauth.routes()))

passport_config.js

const passport = require('koa-passport')
const LocalStrategy = require('passport-local')
const UserModel = require(__dirname + '/../../src/model/UserModel')

passport.use(new LocalStrategy(

    function(username, password, done) {
        UserModel.findOne({ username: username }).then(function(result) {
            if (result != null) {
                if (result.password == password) {
                    return done(null, result);
                } else {
                    log.error('密码错误');
                    return done(null, false, { message: '密码错误' })
                }
            } else {
                log.error('用户不存在');
                return done(null, false, { message: '用户不存在' })
            }
        }).catch(function(err) {
            log.error(err.message);
            return done(null, false, { message: err.message })
        });
    }
));

passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(user, done) {
    console.info(user)
    return done(null, user);
});

router_auth.js

const Router = require('koa-router')
const log = require('tracer').colorConsole({ level: require('config').get('log').level })
const router = new Router()
const passport = require(__dirname + '/passport_config.js')

router.post('/login', function(ctx, next) {
    return passport.authenticate('local', function(err, user, info, status) {
        if (user === false) {
            ctx.body = { success: false }
            ctx.throw(401)
        } else {
            ctx.body = { success: true }
            return ctx.login(user)
        }
    })(ctx, next)
})

router.post('/test', function(ctx, next) {
    if (ctx.isAuthenticated()) {
        console.info('认证通过')
        return next()
    } else {
        ctx.body = '非法访问'
    }
})

module.exports = router

I try http://localhost/login,it work
But I try http://localhost/test,it doesn't work,it is always false,and passport.deserializeUser has never been called

I am very looking forward to your help,and sorry for my pool english

rkusa commented

Hm, I do not see an error, yet. Is passport.serializeUser being called?

rkusa commented

I've updated a koa-passport-example branch to be more closely to what you are doing and it is working fine. Would you mind checking whether https://github.com/rkusa/koa-passport-example/tree/issue_100 does work for you?

Temporarily use

export async function authenticatedUser(ctx: Router.IRouterContext, next: () => Promise<any>) {
    if (ctx.session.passport.user && ctx.session.passport.user.user) {
        ctx.state.user = ctx.session.passport.user.user;
        await next();
    } else {
        ctx.throw(401, 'authenticate please');
    }
}
rkusa commented

Are there any updates on this issue? @gyeongmin-ji thanks for the workaround. Do you have a similar issue, which requires this workaround?

I'm having the same issue, but my situation is a bit weird. This is my code:

import Router from 'koa-router'
import passport from 'koa-passport'
import { setUserData } from '../../utils'
import { User, Bus } from '../../../models'

const auth = new Router({ prefix : 'auth' })

const isAuthenticated = async (ctx, next) => {
  try {
    if(ctx.isAuthenticated()) {
      const { user } = ctx.state
    
      const data = await setUserData(user)
    
      return ctx.body = { ok : true, data : { userInfo : data }, message : '' }
    }
  } catch (e) {
    console.log(e)
  }

  return next()
}

auth.post('/login', isAuthenticated, ctx =>
  passport.authenticate('local', async (err, user, msg) => {
    const { driverToken } = ctx.request.body

    if(user) {
      await User.findByIdAndUpdate(user, { lastSession : Date.now() })
      await ctx.login(user)

      const data = await setUserData(user)

      return ctx.body = { ok : true, data : { userInfo : data }, message : '' }
    }

    ctx.status = 401 // unauthorized

    return ctx.body = { ok : false, data : null, message : msg }
  })(ctx)
)

auth.get('/check-auth', async ctx => {
  console.log(`User is ${ ctx.isAuthenticated() ? '' : 'not' } authenticated`)
  
  if(ctx.isAuthenticated()) {
    console.log('Inside, boys!')

    const data = await setUserData(ctx.state.user)

    return ctx.body = { ok : true, data : { userInfo : data }, message : '' }
  }

  return ctx.body = { ok : false, data : null, message : 'There is no saved session available' }
})

My situation is the following:

  1. I refresh the page, a request to /check-auth is made, and ctx.isAuthenticated() returns false (as expected)
  2. I log in, the session is stored and user logged. Nothing different.
  3. I log out, ctx.logout() is called.
  4. If I refresh the page, step 1 is made. Great, that's how's supposed to work, because I logged out. But if I reload while being logged in, /check-auth returns false.
  5. If I try to log in after logging out, ctx.isAuthenticated() returns true.

Not sure if this is a bug, or if this is supposed to work like this.

My setup:
"koa": "next",
"koa-passport": "^4.0.1"
"koa-router": "^7.0.1"
"koa-session": "^5.5.1"

Any idea why is this happening? Or something I could work around? I tried the solution up there and it didn't work (passport returning undefined in /check-auth, on ctx.session.passport)

Bonus: If I set to request /check-auth after being logging out, it also returns false (including returning undefined when checking on ctx.session.passport, but if I log back in, the object exists.

Also, when I try to log in in another browser (different user, different cookies), the object appears with only one user, not storing the one already logged in, but instead overwriting it.

Got the same problem, however latest solution doesn't work for me, I already have such order, but it still doesn't call deserialize method. However ctx.session is populated with correct session.

It seems this module is absolutely incompatible with koa-session when external session storage is used.

rkusa commented

It seems this module is absolutely incompatible with koa-session when external session storage is used.

Looks like it, as also mentioned in other issues. If someone is going to provide a bare minimum app with this failing setup, I am willing to investigate. Other than that, there are other session middlewares out there that seem to work fine with an external session store.