总是返回 401 Unauthorized in passport-jwt

Posted

技术标签:

【中文标题】总是返回 401 Unauthorized in passport-jwt【英文标题】:Always returning 401 Unauthorized in passport-jwt 【发布时间】:2021-10-11 12:34:09 【问题描述】:

这是我的 req.hearders:


  authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYxMDk2Y2Q1MjViNDU5NDY2MDRmYzhiMSIsImVtYWlsIjoibnZhbmhhaWRhbmdAZ21haWwuY29tIiwiaWF0IjoxNjI4MTQ3NzMyfQ.DSZf03dckfyeA8LmScS1jqymqsSUmSb0f8ywihBmvp0',
  'content-type': 'application/json',
  'user-agent': 'PostmanRuntime/7.28.2',
  accept: '*/*',
  'postman-token': '6072dba7-0985-4dc2-9294-0135868dcbfe',
  host: 'a.seito.backend.utility.api:3000',
  'accept-encoding': 'gzip, deflate, br',
  connection: 'keep-alive',
  'content-length': '212',
  cookie: 'connect.sid=s%3AAPXZrYtAxMnQuOI-XFJ2h-bh9UlXLGvU.4R7DScHcCIaL0qHdl%2FugEs%2FABOf1ZgcypFGIhQep%2FMo; lang=en'

令牌负载:


  "id": "61096cd525b45946604fc8b1",
  "email": "nvanhaidang@gmail.com",
  "iat": 1628260741,
  "exp": 1714660741

我试过了:

opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("Bearer");
opts.jwtFromRequest = ExtractJwt.fromHeader("authorization");

签名时我确实没有在令牌上设置到期时间

const token = jwt.sign(user, config.secrets.jwt,  expiresIn: 86400 * 7 );

./lib/passport/index.js

const passport = require("passport");
const LocalStrategy = require("./strategy/passport_local");
const JWTStrategy = require("./strategy/passport_jwt");

passport.use("local", LocalStrategy);
passport.use("jwt", JWTStrategy);

module.exports = passport;

./lib/passport/strategy/passport_jwt.js

const config = require("../../../lib/config");
// const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
let Account = require("../../../database/models").Account;

const opts = ;
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("Bearer");

opts.secretOrKey = config.passport.secret;
opts.issuer = "accounts.examplesoft.com";
opts.audience = "yoursite.net";

module.exports = new JwtStrategy(opts, async function (jwt_payload, cb) 
  await Account.findOne( email: jwt_payload.email , function (err, account) 
    if (err) 
      return cb(err, false);
    
    if (!account) 
      console.log("jwt_payload", jwt_payload);
      return cb(null, false,  message: "Account is not available" );
    
    if (!account.verifyPassword(password)) 
      return cb(null, false,  message: "Incorrect password." );
    
    var account_result = 
      id: account[config.database.underscoreId],
      name: account.name,
      email: account.email,
    ;
    console.log(account_result);
    return cb(null, account_result);
  );
);

./lib/passport/strategy/passport_local.js

const config = require("../../../lib/config");
const LocalStrategy = require("passport-local").Strategy;
const jwt = require("jsonwebtoken");

const Account = require("../../../database/models").Account;

const opts = 
  usernameField: "login_email",
  passwordField: "login_password",
  session: true,
;

module.exports = new LocalStrategy(opts, async function (
  email,
  password,
  callback
) 
  console.log(email, password);
  await Account.findOne( email: email , function (err, account) 
    if (err) return callback(err, false);

    if (!account) 
      return callback( message: "Account not found" , false, 
        message: "Account is not available",
      );
    

    if (!account.comparePassword(password)) 
      return callback(null, false, 
        message: "Incorrect password",
      );
    
    let account_result = 
      id: account[config.database.underscoreId],
      email: account.email,
    ;
    account_result.token = jwt.sign(account_result, config.passport.secret, 
      expiresIn: config.passport.expiresIn,
    );
    account_result.name = account.name;

    return callback(null, account_result);
  );
);

./routes/index.js

require("dotenv").config();
let express = require("express");
const  __  = require("i18n");
let router = express.Router();
const passport = require("passport");

router.get(
  "/",
  passport.authenticate("jwt",  session: false ),
  async function (req, res, next) 
    console.log(req.err);
    if (req.is("application/*") || req.is("json")) 
      res.status(200).json(
        success: true,
        message: __("Welcome to") + " " + process.env.APP_NAME,
      );
     else 
      res.render("index", 
        title: process.env.APP_NAME,
      );
    
  
);

module.exports = router;

./app.js

const config = require("./lib/config");
const express = require("express");
const passport = require("./lib/passport");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const session = require("express-session");

const app = express();

const indexRouter = require("./routes/index");
const authRouter = require("./routes/auth");

app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

app.use(bodyParser.json());
app.use(bodyParser.urlencoded( extended: false ));

app.use(session(config.session));
app.use(cookieParser(config.cookie.secret));

app.use(express.static(path.join(__dirname, "public")));

// passport
passport.serializeUser(function (account, cb) 
  process.nextTick(function () 
    cb(null,  id: account.id, name: account.name, email: account.email );
  );
);
passport.deserializeUser(function (account, cb) 
  process.nextTick(function () 
    return cb(null, account);
  );
);

app.use(passport.initialize());
app.use(passport.session());

// routes
app.use("/", indexRouter);
app.use("/auth", authRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) 
  res.status(404);

  // respond with html page
  if (req.accepts("html")) 
    res.render("errors/404", 
      title: "Not Found" + " - " + config.env.APP_NAME,
      url: req.url,
    );
    return;
  

  // respond with json
  if (req.accepts("json")) 
    res.render("errors/404",  url: req.url );
    return;
  

  // default to plain-text. send()
  res.type("txt").send(__("Not found"));
);

// error handler
app.use(function (err, req, res, next) 
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = config.env.NODE_ENV === "dev" ? err : ;

  logger.error("[" + err.name + "] request error: " + err.message);
  // render the error page
  if (config.env.NODE_ENV === "dev") 
    res.status(err.status || 500).render("error");
   else 
    res.status(err.status || 500).json(
      success: false,
      message: "Internal error. [" + err.name + "] " + err.message,
    );
  
);

module.exports = app;

登录成功但响应 401 - 通过 passport-jwt 进行身份验证时未授权:

我找不到解决此问题的解决方案,请帮助我!非常感谢!

【问题讨论】:

【参考方案1】:

token 似乎不包含发布者和受众声明

opts.issuer = "accounts.examplesoft.com";
opts.audience = "yoursite.net";

令牌负载应该是


  "id": "61096cd525b45946604fc8b1",
  "email": "nvanhaidang@gmail.com",
  "iss": "accounts.examplesoft.com", // ADD THIS!!!
  "aud": "yoursite.net",  // ADD THIS!!!
  "iat": 1628260741,
  "exp": 1714660741

【讨论】:

我删除了:opts.issuer = "accounts.examplesoft.com"; opts.audience = "yoursite.net";并再次尝试,问题仍然存在【参考方案2】:

我通过重新设置护照、本地护照、护照-jwt 和使用解决了我的问题:

opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();

下面的另一个不起作用,我不知道为什么:

opts.jwtFromRequest = ExtractJwt.fromHeader("Authorization");
opts.jwtFromRequest = ExtractJwt.fromBodyField("token");
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("Bearer");

【讨论】:

以上是关于总是返回 401 Unauthorized in passport-jwt的主要内容,如果未能解决你的问题,请参考以下文章

Springboot actuator refresh 和 bus-refresh 总是返回 401 Unauthorized

带有 Vuejs 的 Laravel 7.x Sanctum (SPA) 总是返回 401 Unauthorized

RestTemplate请求出现401错误

Django Tastypie 总是返回 401 未经授权

WCF Rest 自托管证书安全服务返回 401 未经授权

护照-jwt 总是返回 401 未授权