我的Nest.js应用程序使用Google OAuth进行身份验证时遇到了一个问题。Nest.js后端运行在端口5000上,前端(Next.js)运行在端口3000上。我已经使用正确的origin URI和redirect URI设置了Google Cloud Console,两者都设置为“http://localhost:3000”。
我在frontend Next.js中遇到以下错误
- CORS策略已阻止从源“http://localhost:3000”访问位于“https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000&scope=email%20profile&client_id=${GOOGLE_OAUTH_CLIENT_ID}”(从“http://localhost:5000/auth/google '重定向)的XMLHttpRequest:所请求的资源上不存在”Web-Control-Allow-Origin“标头。
- GET https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000&scope=email%20profile&client_id=${GOOGLE_OAUTH_CLIENT_ID} net::ERR_FAQs 302(Found)
以下是我的Nest.js Auth Controller、Google OAuth Strategy和Google OAuth Guard的片段:
//Nest.js google oauth策略
export class GoogleOAuthStrategy extends PassportStrategy(Strategy, 'google') {
constructor(private readonly configService: ConfigService) {
super({
clientID: configService.get('googleOAuthClientId'),
clientSecret: configService.get('googleOAuthClientSecret'),
callbackURL: configService.get('googleOAuthCallbackURL'),
scope: ['email', 'profile'],
});
}
async validate(
accessToken: string,
refreshToken: string,
profile: Profile,
done: VerifyCallback,
): Promise<any> {
const { id, name, emails, photos } = profile;
const user: User = {
type: 'individual',
email: emails[0].value,
firstName: name.givenName,
lastName: name.familyName,
picture: photos[0].value,
authenticationProviders: [{ name: 'google', id }],
};
done(null, user);
}
}
字符串
//Nest.js google oauth guard
export class GoogleOAuthGuard extends AuthGuard('google') {
constructor() {
super({
accessType: 'offline',
});
}
}
型
//Nest.js auth控制器
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Get('google')
@UseGuards(GoogleOAuthGuard)
async googleAuth() {
return HttpStatus.OK;
}
@Get('google-redirect')
@UseGuards(GoogleOAuthGuard)
googleAuthRedirect(
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
) {
return this.authService.login(req, res, 'google');
}
}
型
//Nest.js验证服务
export class AuthService {
constructor(
private readonly configService: ConfigService,
private readonly usersService: UsersService,
private readonly jwtService: JwtService,
) {}
async login(req: Request, res: Response, provider: Provider): Promise<void> {
const user = req.user as User;
if (!user) {
throw new NotFoundException(`No user from ${provider}`);
}
let userPayload: User;
let accessTokenPayload: string;
const foundUser = await this.usersService.findByEmail(user.email);
if (foundUser) {
const providerExists = foundUser.authenticationProviders.some(
(provider) => provider.name === user.authenticationProviders[0].name,
);
// User found with different provider
if (!providerExists) {
foundUser.authenticationProviders.push(user.authenticationProviders[0]);
await foundUser.save();
}
userPayload = foundUser;
accessTokenPayload = foundUser._id.toString();
} else {
// Save user to mongodb if it does not exists already
const newUser = await this.usersService.create(user);
userPayload = newUser;
accessTokenPayload = newUser._id.toString();
}
const accessToken = this.jwtService.sign({ id: accessTokenPayload });
res.cookie('CARDTRIKA_ACCESS_TOKEN', accessToken, {
maxAge: this.configService.get('cookieMaxAge'),
httpOnly: true,
});
res.status(HttpStatus.OK).json({
statusCode: HttpStatus.OK,
success: true,
message: 'User information',
data: userPayload,
});
}
}
型
如果我直接从浏览器向http:localhost:5000/auth/google
发出get请求,它会重定向到google API > consent屏幕,然后我可以通过gmail帐户登录,最后可以成功获取用户信息。但Next.js不会发生同样的情况。一旦我发出请求,它就会说CORS错误。
解决方案:
所以,基本上有两个端点。/auth/google
和/auth/google-redirect
。在google控制台上,origin-uri应该是http://localhost:3000,redirect-uri应该设置为http://localhost:3000/auth/google-redirect(无论我们想在前端管理什么)。
现在我们必须从origin localhost:5000请求到/auth/google。所以我做了如下,
const handleLogin = async (method: string) => {
window.location.replace(`${apiBaseUrl}/auth/${method.toLowerCase()}`);
};
型
因此,它打开同意屏幕,登录后,它将重定向到http://localhost:3000/auth/google-redirect?code=<some-code-and-other-things>
和它的前端我已经管理这个URL页面,并提出了另一个请求,以http://localhost:5000/auth/google-redirect与queryString。所以,在后端现在,谷歌的战略知道它的身份验证,由于它提供的已知代码,并给予我们用户的详细信息。
1条答案
按热度按时间pvabu6sv1#
我很乐意帮助你
我认为问题是你没有在你的后端设置
cors
域,以允许接收来自其他域的请求。在 Bootstrap 中,写入
app.enableCors({origin: corsDomains})
,其中corsDomains
是域的数组,(例如http://localhost:3000
)