使用passport-jwt授权jwt令牌时出现401未经授权状态

4
成功登录后,我获得了jwt令牌,现在为了访问受限API,我发送了授权头,但我始终收到“401未经授权”的错误。我参考了这里提出的使用passport-jwt验证节点API问题,但并没有帮助我。这是我调用以访问来自受限API的数据的函数。
check() {
    console.log(this.token);
    var headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append("Authorization", "Bearer" +  this.token);
    let url = this.authenticationEndPoint + 'random';
    this.checkauth(url, headers).subscribe(
        data => {
            console.log(data);
        },
        error => {
            console.log("error");
        }
    );
}

checkauth(url:string, header:any): Observable<any> {

    return this.http.get(url, header)
            .map(this.extractData)
            .catch(this.handleError);
}
private extractData(res: Response) {
    let body = res;
    return body || {};
}

这是我的Node.js服务器上发送JWT令牌的登录代码:

app.post('/login_mobile', function(req, res) {
    if(!(req.body.email && req.body.passpord)) {
        user.findOne({'local.email' : req.body.email}, function(err, user) {
            if (err) { return done(err);}

            if (!user) {
                return res.json(200, "email is wrong");
            }
            if(!user.validPassword(req.body.password)) {
                return res.json(200, "wrong password");
            }
            var token = jwt.encode(user, configAuth.secret);
            return res.json(200, { user: user, jwtToken: token });
        });
    }
    else {
        res.send("no credentials provided");
    }
});

响应受限制的API请求的代码

app.get('/random', passport.authenticate('jwt', { session: false }),
    function(req, res) {
        res.send("success");
    });

这是我用来验证用户身份的护照策略,但奇怪的是它甚至没有打印这里,仍然发送401状态。
var opts = {};
opts.secretOrKey = configAuth.secret;
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
passport.use(new JwtStrategy(opts, function(jwt_payload, done){
    console.log("here");
    console.log(jwt_payload);
    User.findOne({_id: jwt_payload._id}, function(err, found_user) {
        if (err) {
            return done(err, false);
        }
        if(found_user !== null) {
            res.send("finally");
        }
        else {
            res.send("authentication failed");
        }
        return found_user ? done(null, found_user) : done(null, false);
    })
}));

如果有人能指出我的错误,请告诉我。

2个回答

3
我替换了一个类似的问题,解决方法是将以下内容替换为:
jwtFromRequest: ExtractJwt.fromAuthHeader(),

使用:

jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),

2
更新:本答案使用了ExtractJwt.fromAuthHeader,该方法已经被弃用。现在已经更新为使用ExtractJwt.fromAuthHeaderWithScheme('jwt')
我遇到了这个问题,花了几个小时才解决。答案与这里的答案类似:使用passport-jwt对node API进行身份验证passport本地策略未被调用
导致调试困难的原因是如果策略没有得到预期的信息,它们甚至不会运行。在后者中,由于没有收到用户名和密码,LocalStrategy验证回调未被启动。
在我的情况下,可能与你的情况相同,JWT令牌没有以正确的格式在标头中提供。这是因为在成功登录后,我返回的令牌是这样的:
res.status(200).json({
    token: `JWT${generateToken(userInfo)}`,
    user: userInfo,
});

当我应该做这个的时候:

res.status(200).json({
    token: `JWT ${generateToken(userInfo)}`,
    user: userInfo,
});

注意 JWT 后面的空格。因此,当我的 jwtStrategy 函数接收到类似于 JWTx759ghv... 的身份验证令牌时,它期望的是 JWT x759ghv...

如果 Passport 能为此抛出警告就太方便了!

以下是完整的设置,希望对您有所帮助:

// passportService.js

const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');

const User = require('../models/User');
const config = require('../config');

/**
* Local Login Strategy
*/

const localOptions = {
    usernameField: 'email',
};

const localLogin = new LocalStrategy(localOptions, (email, password, done) => {
    console.log('Using Local strategy');
    console.log(email, password);
    User.findOne({ email }, (err, user) => {
        if (err) { return done(err); }
        if (!user) { return done(null, false, { message: 'Your login details could not be verified. Please try again.' }); }

        user.comparePassword(password, (passwordErr, isMatch) => {
            if (passwordErr) { return done(passwordErr); }
            if (!isMatch) { return done(null, false, { message: 'Your login details could not be verified. Please try again.' }); }
            return done(null, user);
        });
        return false;
    });
});


/**
* JWT Strategy
*/

const jwtOptions = {
    /*
     * Deprecated: fromAuthHeader() - see update above
    jwtFromRequest: ExtractJwt.fromAuthHeader(),
     */

    jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme("jwt"),
    secretOrKey: config.auth.passport.key,
};

console.log(jwtOptions);

const jwtLogin = new JwtStrategy(jwtOptions, (payload, done) => {
    User.findById(payload._id, (err, user) => {
        if (err) {
            return done(err, false);
        }
        if (user) {
            done(null, user);
        } else {
            done(null, false);
        }
    });
});

passport.use(localLogin);
passport.use(jwtLogin);

module.exports = {
    initialize: () => passport.initialize(),
    authenticateJWT: passport.authenticate('jwt', { session: false }),
    authenticateCredentials: passport.authenticate('local', { session: false }),
};

然后,在我的路由中使用:
// ... after of the other Express app initialization

const passportService = require('./services/passport');
const AuthenticationController = require('./controllers/Authentication');

const requireToken = passportService.authenticateJWT;
const requireCredentials = passportService.authenticateCredentials;

app.use(passportService.initialize());

authRoutes.post('/register', AuthenticationController.register);
apiRoutes.get('/protected', requireToken, AuthenticationController.login);
authRoutes.post('/login', requireCredentials, AuthenticationController.login);

如果您仍然遇到问题,请在调用策略之前运行一个小型中间件,以确保您发送的标头格式正确:

apiRoutes.get('/protected', (req, res) => {
  console.log(req.headers);
}, requireToken, AuthenticationController.login);

我看到了 TypeError: ExtractJwt.fromAuthHeader 不是一个函数。 - ggnoredo
@ggnoredo,看起来这个函数已经被弃用了。我已经更新了我的评论 - Donato在这个线程中的答案有一个类似的解决方案。 - Good Idea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接