facebook - 如何在 Nestjs facebook 策略回调 url 中传递动态参数
问题描述
如何在 facebook 登录回调 url 中传递一些动态参数?
我有不同类型的用户(由“类型”参数区分)使用 facebook 登录进行注册。我已经使用 passport-facebook 创建了一个 facebook 身份验证策略,效果很好。
但是在身份验证之后,当回调 url 被调用时,我需要知道哪种类型的用户请求注册。
我猜我可以在定义回调 url 时传递一个参数
像这样的东西
http://localhost:3000/auth/facebook/callback/type1 http://localhost:3000/auth/facebook/callback/type2
如何将动态值传递到 FacebookStrategy?
或者有什么可能的解决方法来实现这一目标?
// PassportStrategy.ts
@Injectable()
export class FacebookStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
clientID: 'MYID',
clientSecret: 'MYSCRET',
callbackURL: "http://localhost:3000/auth/facebook/callback",
profileFields: ['id', 'displayName', 'emails', 'photos']
});
}
async validate(accessToken: any, refreshToken: any, profile: any) {
return {
name: profile.displayName,
email: profile.emails[0].value,
provider: "facebook",
providerId: profile.id,
photo: profile.photos[0].value
}
}
}
// 认证控制器
@Controller('auth')
export class AuthController {
constructor(
@Inject(forwardRef(() => AuthService)) private readonly authService: AuthService,
) { }
@Get('/facebook')
@UseGuards(AuthGuard('facebook'))
async facebookAuth(@Request() req) {
return
}
@UseGuards(AuthGuard('facebook'))
@Get('/facebook/callback')
async facebookCallback(@Request() req) {
return this.authService.login(req.user);
}
}
基本上我希望能够调用“/auth/facebook/:type”并在策略中定义的回调 url 中传递类型值
和回调端点类似于“/auth/facebook/callback/:type”
因此,当我调用 authservice.login 函数时,我可以传递该“类型”并决定在第一次注册时创建哪种类型的用户
如果我的方法是错误的,请指导我。谢谢
解决方案
我最近一直在处理一个类似的问题,这是我的方法。可能不是最好的,但现在可以使用。
import { Inject, Injectable, Logger } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import passport = require('passport');
import { Strategy } from 'passport-facebook';
@Injectable()
export class FacebookStrategy extends PassportStrategy(Strategy, 'facebook') {
private readonly logger = new Logger(FacebookStrategy.name);
constructor(
@Inject('FACEBOOK_STRATEGY_CONFIG')
private readonly facebookStrategyConfig,
) {
super(
facebookStrategyConfig,
async (
request: any,
accessToken: string,
refreshToken: string,
profile: any,
done,
) => {
this.logger.log(profile);
// take the state from the request query params
const { state } = request.query;
this.logger.log(state);
// register user
// return callback
return done(null, profile);
},
);
passport.use(this);
}
}
import { Controller, Get, HttpStatus, Inject, Param, Query, Req } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Redirect } from '@nestjsplus/redirect';
@Controller('auth')
export class AuthController {
@Inject('ConfigService')
private readonly configService: ConfigService;
@Get(':provider/callback')
@Redirect()
async socialCallback(@Req() req, @Param('provider') provider: string, @Query('state') state: string) {
// here you can use the provider and the state
return {
statusCode: HttpStatus.FOUND,
url: `${this.configService.get('FRONTEND_HOST')}/dashboard`,
};
}
}
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AuthController } from './auth.controller';
import { FacebookStrategy } from './facebook.strategy';
import passport = require('passport');
const facebookStrategyConfigFactory = {
provide: 'FACEBOOK_STRATEGY_CONFIG',
useFactory: (configService: ConfigService) => {
return {
clientID: `${configService.get('FACEBOOK_CLIENT_ID')}`,
clientSecret: `${configService.get('FACEBOOK_CLIENT_SECRET')}`,
callbackURL: `${configService.get('FACEBOOK_OAUTH_REDIRECT_URI')}/callback`,
profileFields: ['id', 'displayName', 'link', 'photos', 'emails', 'name'],
passReqToCallback: true,
};
},
inject: [ConfigService],
};
@Module({
controllers: [AuthController],
providers: [facebookStrategyConfigFactory, FacebookStrategy],
})
export class AuthModule implements NestModule {
public configure(consumer: MiddlewareConsumer) {
const facebookLoginOptions = {
session: false,
scope: ['email'],
state: null,
};
consumer
.apply((req: any, res: any, next: () => void) => {
const {
query: { state },
} = req;
facebookLoginOptions.state = state;
next();
}, passport.authenticate('facebook', facebookLoginOptions))
.forRoutes('auth/facebook/*');
}
}
现在让我解释一下:D。诀窍在于中间件配置。
const facebookLoginOptions = {
session: false,
scope: ['email'],
state: null,
};
consumer
.apply((req: any, res: any, next: () => void) => {
const {
query: { state },
} = req;
facebookLoginOptions.state = state;
next();
}, passport.authenticate('facebook', facebookLoginOptions))
.forRoutes('auth/facebook/*');
因此,oAuth 具有此功能,您可以通过登录流程传递状态参数。通过在变量中提取护照选项,我们可以通过在护照之前应用另一个中间件来动态更改状态参数。这样,您现在可以调用http://localhost:3000/auth/facebook/login?state=anything-you-want
,此state
查询参数将通过策略传递,也会在回调调用中传递。
我还使用示例创建了一个 git repo:https ://github.com/lupu60/passport-dynamic-state
推荐阅读
- c# - 在 TabControl 中为同一表单显示不同的选项卡
- influxdb - 如何通过 Flux 使用变量访问成员
- ruby-on-rails - puppeteer PDF 忽略背景颜色
- javascript - 为什么 Naked 会错误地执行代码?
- flutter - 如何在一个容器中显示日期和工作日
- sql - 数据透视表:如果参数之一为空,则加入同一记录
- delphi - Delphi Soap 服务器上的基本身份验证标头解析
- flutter - Flutter 状态管理,无法实时刷新
- timescaledb - Timescaledb 压缩、segmentby 和分块
- c# - CS8625 无法将 null 文字转换为 Interlocked.Exchange(ref c, null) 的不可为 null 的引用类型警告