【问题标题】:using koa and passport for authenication使用koa和passport进行认证
【发布时间】:2015-10-30 23:39:44
【问题描述】:

我正在使用 koa 和 passport 尝试实现中间件,以防止在未经身份验证时访问 URI。

var koa = require('koa');
var session = require('koa-generic-session');
var bodyParser = require('koa-bodyparser');
var koaRouter = require('koa-router');
var passport = require('koa-passport');
var views = require('co-views');
var render = views('.', { map: { html: 'swig' }});
var localStrategy = require('passport-local').Strategy;

var app = koa();
var router = koaRouter();

app.keys = ['secret'];
app.use(session());
app.use(bodyParser());
app.use(passport.initialize());
app.use(passport.session());

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

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

passport.use(new localStrategy(function(username, password, done) {
    if (username === 'user1' && password === 'password2') {
        done(null, { userId: 99, userName: 'redBallons' });
    } else {
        done(null, false);
    }
}));

router.get('/login', function *(next) {
    this.body = yield render('index.html');
});

router.post('/login', passport.authenticate('local', {
    successRedirect: '/secretBankAccount',
    failureRedirect: '/login'
}));

router.get('*', function *(next) {
    if (! this.isAuthenticated()) {
        console.log('not authenticated');
        this.redirect('/login');
    } else {
        console.log('authenticated');
        yield next;
    }
});

router.get('/secretBankAccount', function *(next) {
    this.body = '2 dollars';
});

app.use(router.routes());
app.listen(8080);

但是,我永远无法访问我的 secretBankAccount。我可以输入正确的用户和密码,并且可以看到经过身份验证的消息,但是 router.get('*') 中的 yield next 并没有将我传递到下一个路由函数

【问题讨论】:

    标签: authentication routing passport.js koa


    【解决方案1】:

    当使用koa-router 时,预计只会命中一条路线。因此,当您到达 '*' 路线时,即使您 yield next 也不会到达另一条路线。

    所以你应该用自己的身份验证中间件替换通用路由:

    app.use(function*(next) {
      if (this.isAuthenticated()) {
        yield next
      } else {
        this.redirect('/login')
      }
    });
    

    身份验证中间件将强制您使用两个路由对象而不是一个来进行路由。这样您就可以区分公共路由和安全路由。所以像:

    var public = new koaRouter();
    
    public.get('/login', function *(next) {
        this.body = yield render('index.html');
    });
    
    public.post('/login', passport.authenticate('local', {
        successRedirect: '/secretBankAccount',
        failureRedirect: '/login'
    }));
    
    app.use(public.routes());
    
    app.use(function*(next) {
      if (this.isAuthenticated()) {
        yield next;
      } else {
        this.redirect('/login');
      }
    })
    
    var secured = new koaRouter();
    
    secured.get('/secretBankAccount', function *(next) {
      this.body = '2 dollars';
    });
    
    app.use(secured.routes());
    

    在上面的示例中,请求将首先到达公共路由中间件。然后,如果它与当前请求与公共路由不匹配,它将移至身份验证中间件。如果isAuthenticated()false,则会发生重定向。如果isAuthenticated()true,它将进入安全路由。

    此方法基于the koa-passport-example projectkoa-passport 的作者创建。

    【讨论】:

    • 谢谢。一个更正,在路由器中间件 app.use(function*(next) 中,需要添加一个检查以确保它不是“/登录”路由。似乎重定向完成后,路由器中间件会再次被调用。
    • @mfc 重定向总是会强制再次调用路由器中间件,因为这是重定向的本质(即客户端发送另一个 HTTP 请求)。如果这不是您的首选方法,您可以只发送 HTTP 状态 401(未经授权),而不是重定向并在客户端处理失败的请求。
    【解决方案2】:

    peadar-doyle 的回答是这样做的方法,但需要更新以避免警告:koa deprecated Support for generators will be removed in v3.

    这是更新版本。我发送 401 而不是重定向:

    // all requests must now be authenticated
    app.use(async (ctx, next) => {
        if (ctx.isAuthenticated()) {
            await next();
        } else {
            ctx.body = "access denied";
            ctx.status = 401;
        }
    })
    

    【讨论】:

      猜你喜欢
      • 2020-01-20
      • 2023-03-25
      • 1970-01-01
      • 2020-05-02
      • 2019-12-20
      • 2018-09-22
      • 2016-10-03
      • 2019-11-29
      • 1970-01-01
      相关资源
      最近更新 更多