You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Angular集成Passport登录功能故障排查求助

问题:Node.js + Angular 中 Passport 登录无响应,findOne() 执行异常

点击登录按钮后UI无任何反应,无法跳转到首页。核心问题出在Passport配置环节:代码无法执行完findOne()方法,后续逻辑及console.log均未触发。控制台仅输出Sequelize警告:传入模型korisnik的查询属性(email)未设置where条件,执行了无限制的SELECT语句;即使手动添加where子句,也仅显示SELECT语句,无后续执行。


相关代码

login.component.ts

signupForm!: FormGroup;
constructor(private router:Router, private userService: UserService) { }

ngOnInit(): void {
  this.signupForm = new FormGroup({
    'email': new FormControl(null,[Validators.required]),
    // 'email': new FormControl(null,[Validators.required,Validators.email]),
    'password': new FormControl(null,Validators.required)
  })
}

onSubmit(){
  this.userService.login(JSON.stringify(this.signupForm.value)).subscribe(data=>{console.log('Success');this.router.navigate(['/home']);}, error=>console.log(error))
}

前端Service

return this.http.post(this.apiUrlL,body,{
  observe:'body',
  withCredentials:true,
  headers:new HttpHeaders().append('Content-Type','application/json')
});

前端Model

export class UserModel {
  public id!: number;
  public ime!: string;
  public prezime!: string;
  public email!: string;
  public password!: string;
  
  constructor() {}
}

Passport-config(问题核心)

var passport = require("passport"),
  LocalStrategy = require("passport-local").Strategy;
const UserCont = require("../controller/user-cont");
var User = require("../model/user_data");

passport.use(
  "local",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
    },
    function (username, password, done) {
      User.User.findOne({ email: username }, function (err, user) {
        if (err) {
          return done(err, { message: "testcase." });
        }
        if (!user) {
          return done(null, false, { message: "Incorrect username." });
        }
        if (!UserCont.isValid(user.email, password)) {
          return done(null, false, { message: "Incorrect password." });
        }
        console.log("passport user", username);
        return done(null, user);
      });
    }
  )
);

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

passport.deserializeUser(function (id, done) {
  User.User.findById(id, function (err, user) {
    done(err, user);
  });
});

后端login.js

var User = require("../model/user_data");
var passport = require("passport");

module.exports.loginUser = (req, res, next) => {
  passport.authenticate("local", function (err, user, info) {
    if (err) {
      return res.status(501).json(err);
    }
    if (!user) {
      return res.status(501).json(info);
    }
    req.logIn(user, function (err) {
      if (err) {
        return res.status(501).json(err);
      }
      return res.status(200).json({ message: "Login Success" });
    });
  })(req, res, next);
};

后端User-controller

module.exports.isValid = (email, newPass) => {
  const salt = crypto.genSalt(10);
  const hashPass = crypto.hash(newPass, salt);
  User.User.findOne({ email: email }).then((user) => {
    crypto.compare(user.password, hashPass, function (err, ifValid) {
      if (ifValid == true) {
        console.log(ifValid);
        return true;
      }
    });
  });
};

后端User-routing文件

const express = require("express");

const Login = require("../common/login");
const router = express.Router();
router.post("/login", Login.loginUser);
module.exports = router;

后端App.js(Passport相关部分)

//passport
var passport = require("passport");
var session = require("express-session");

app.use(
  session({
    name: "Session ID",
    resave: false,
    saveUninitialized: false,
    secret: "secret",
    cookie: {
      maxAge: 36000000,
      httpOnly: false,
      secure: false,
    },
  })
);
require("./common/passport-config");
app.use(passport.initialize());
app.use(passport.session());
//

app.use(express.json());

app.use("/api", userRouting);

后端DB Model

const Sequelize = require("sequelize");
const sequelize = require("./../common/db-config");
const Model = Sequelize.Model;

//User
class User extends Model {}

User.init(
  {
    id: {
      type: Sequelize.INTEGER,
      allowNull: false,
      primaryKey: true,
      autoIncrement: true,
      field: "id",
    },
    ime: {
      type: Sequelize.STRING,
      allowNull: false,
      field: "ime",
    },
    prezime: {
      type: Sequelize.STRING,
      allowNull: false,
      field: "prezime",
    },
    email: {
      type: Sequelize.STRING,
      allowNull: false,
      unique: true,
      field: "email",
    },
    password: {
      type: Sequelize.STRING,
      allowNull: false,
      field: "sifra",
    },
  },
  {
    sequelize,
    modelName: "korisnik",
    tableName: "korisnik",
    timestamps: false,
  }
);

module.exports = { User };

问题排查与修复方案

1. Sequelize 查询语法错误(核心问题)

Sequelize的findOne()需要将查询条件放在where对象中,原代码直接传{ email: username }会被当成查询属性而非条件,导致无限制查询且回调不触发。

修复Passport-config中的findOne:

// 原代码
User.User.findOne({ email: username }, function (err, user) { ... })

// 修改后
User.User.findOne({ where: { email: username } }, function (err, user) { ... })

同时deserializeUser中的findById已废弃,改为findByPk:

passport.deserializeUser(function (id, done) {
  User.User.findByPk(id, function (err, user) {
    done(err, user);
  });
});

2. isValid函数异步逻辑错误

crypto.genSalt、crypto.hash、crypto.compare都是异步方法,原代码同步调用会返回Promise而非实际值,且整个函数没有返回值,导致Passport中!UserCont.isValid()永远为true,直接触发密码错误分支。

修复User-controller中的isValid:

const crypto = require('crypto'); // 记得导入crypto
const User = require("../model/user_data");

module.exports.isValid = async (email, newPass) => {
  try {
    // 用promise版本的crypto方法
    // 验证密码时不需要重新哈希,直接用明文和数据库中的哈希对比
    const user = await User.User.findOne({ where: { email: email } });
    return await crypto.promises.compare(newPass, user.password);
  } catch (err) {
    console.error(err);
    return false;
  }
};

3. Passport LocalStrategy适配异步isValid

因为isValid改成了异步函数,LocalStrategy的回调需要用async/await:

passport.use(
  "local",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
    },
    async function (username, password, done) {
      try {
        const user = await User.User.findOne({ where: { email: username } });
        if (!user) {
          return done(null, false, { message: "Incorrect username." });
        }
        const isValid = await UserCont.isValid(user.email, password);
        if (!isValid) {
          return done(null, false, { message: "Incorrect password." });
        }
        console.log("passport user", username);
        return done(null, user);
      } catch (err) {
        return done(err, { message: "Server error." });
      }
    }
  )
);

4. 前端数据传递错误

前端login方法中用JSON.stringify把表单值转成字符串,但后端用express.json()解析JSON格式的请求体,直接传对象即可,否则后端无法正确解析email和password。

修复login.component.ts中的onSubmit:

onSubmit(){
  this.userService.login(this.signupForm.value).subscribe(
    data => {
      console.log('Success');
      this.router.navigate(['/home']);
    }, 
    error => console.error(error)
  )
}

内容的提问来源于stack exchange,提问作者Drexx_Dusan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:07:12