У меня есть приложение NestJS, в котором есть некоторая логика аутентификации.Вход в систему реализован для Google Oauth с использованием Passport и, кажется, работает, за исключением того, что на сервере я выдам эту ошибку:
(node:19195) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Я немного погуглил и, похоже, одной из распространенных причин может бытьотправьте ответ несколько раз клиенту.Тем не менее, я не могу обнаружить это в своем коде, поэтому я подозрительно, если это причинаВот соответствующие фрагменты.
Использование @ nestjs / passport для сериализации и десериализации пользователя.
@Injectable()
export class GoogleSerializer extends PassportSerializer {
constructor(private readonly usersService: UsersService) {
super();
}
public serializeUser(user: User, done: Function) {
console.log('serialize', user);
if (user) {
done(null, user.id);
} else {
done(null);
}
}
public async deserializeUser(id: number, done: Function) {
console.log('deserialize', id);
this.usersService.findById(id).then(user => {
done(null, user);
}).catch(error => {
done(error, null);
});
}
}
Вот стратегия Google для Passport JS:
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy) {
constructor(private readonly usersService: UsersService) {
super({
clientID:
'client',
clientSecret: 'I'm-secret',
callbackURL: '/auth/google/callback',
scope: ['email', 'profile'],
});
}
async validate(accessToken, refreshToken, profile, done) {
const user = <create the user object from google profile>
this.usersService.findOne(user.email).then(userEntity => {
if (!userEntity) {
this.usersService.createOne(user);
}
});
return this.usersService
.findOne(user.email)
.then(user => {
done(null, user);
return user;
})
.catch(error => {
done(error);
return null;
});
}
}
Вот маршруты для AuthController:
@Controller('auth')
export class AuthController {
@Get('/google/callback')
async googleCallback(@Req() req, @Res() res, @Next() next) {
passport.authenticate('google', {
successReturnToOrRedirect: '/users/test',
failureRedirect: '/auth/login'
})(req, res, next);
}
@Get('/login')
async login(@Req() req) {
return '<a href="/auth/google/login">Login</a>';
}
@Get('/google/login')
async googleLogin(@Req() req, @Res() res, @Next() next) {
passport.authenticate('google', { scope: ['profile', 'email'] })(req, res, next);
}
}
У меня есть промежуточное ПО для путей, по которым пользователь должен войти в систему:
@Injectable()
export class LoginRequired implements NestMiddleware {
resolve(...args: any[]): MiddlewareFunction {
console.log('calling loginrequired');
return (req, res, next) => {
if (!req.isAuthenticated || !req.isAuthenticated()) {
if (req.session) {
req.session.returnTo = req.originalUrl || req.url;
}
return res.redirect('/auth/login');
}
next();
}
}
}
и вот этап установки:
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: true,
cookie: { secure: false }}));
app.use(passport.initialize());
app.use(passport.session());
Например, я пытаюсь зайти / пользователь, который защищен этим промежуточным ПО и который должен отправить пользователя на страницу входа, которая предлагает пользователю войти в систему и приводит пользователя на страницу / пользователя.Все работает, но я получаю
Невозможно установить заголовки после их отправки клиенту
Есть идеи, как это происходит?
Я используюПаспорт и Джест.