Социальный вход в NestJS с использованием @AuthGuard, Passport - PullRequest
0 голосов
/ 08 ноября 2019

Итак, у меня почти закончена попытка реализовать социальный вход в приложение с поддержкой NestJS. У меня есть некоторые проблемы:

Перво-наперво. У меня есть AuthModule, и есть провайдер TwitterGuard:

const twitterOptions: IStrategyOptionWithRequest = {
  consumerKey: process.env[ENV.SOCIAL.TWITTER_CONSUMER_KEY],
  consumerSecret: process.env[ENV.SOCIAL.TWITTER_CONSUMER_SECRET],
  callbackURL: process.env[ENV.SOCIAL.TWITTER_CALLBACK_URL],
  passReqToCallback: true,
  includeEmail: true,
  skipExtendedUserProfile: false,
};

export class TwitterGuard extends PassportStrategy(Strategy, 'twitter') {
  constructor() {
    super(twitterOptions);
  }

  /*  authenticate(req: Request, options?: any): void {
      console.log(req.body);
      // super.(req, options);
    }*/

  // Magical nest implementation, eq to passport.authenticate
  validate(req: Request, accessToken: string, refreshToken: string, profile: Profile, done: (error: any, user?: any) => void) {
    const user: SocialAuthUser = {
      id: profile.id,
      nick: profile.username,
      name: profile.displayName,
    };
    if (profile.emails) {
      user.email = profile.emails.shift().value;
    }
    if (profile.photos) {
      user.avatar = profile.photos.shift().value;
    }

    done(null, user);
  }
}

, а также AuthController:

@Controller('auth')
@ApiUseTags('auth')
export class SocialAuthController {

  constructor(private us: UserService) {
  }

  @Get('twitter')
  @UseGuards(AuthGuard('twitter'))
  twitter() {
    throw new UnauthorizedException();
  }

  @Get('twitter/callback')
  @UseGuards(AuthGuard('twitter'))
  async twitterCallback(@ReqUser() socialUser: SocialAuthUser, @Res() response) {
    const user = await this.us.registerSocialUser(socialUser);
    if (user) {
      // console.log('Redirect', '/some-client-route/token');
      response.redirect(`${SITE_URL}/activate/${user.token}`);
    }
    response.sendStatus(401);
  }

}

Когда я звоню по URL /auth/twitter, защита пинаети перенаправляет на страницу Twitter с просьбой предоставить пользователю доступ к приложению Twitter.

Если пользователь предоставляет доступ, все в порядке, на маршруте обратного вызова (/auth/twitter/callback) TwitterGuard снова включается и обрабатывает пользователяв validate сохраняет до request, и я могу получить к нему доступ в контроллере. Пока все хорошо.

Однако, если пользователь отказывает в доступе к приложению Twitter, охранник возвращает 401 на маршруте обратного вызова даже до того, как будет применен любой из моих методов.

Я пытался играть с authenticate метод, который вызывается (теперь закомментирован в коде), где я мог бы каким-то образом настроить это, но понятия не имею, что возвращать или делать. Если это путь, как мне перенаправить оттуда на страницу авторизации в твиттере, как это делает стратегия паспорта? Что вернуть при обратном вызове, чтобы продолжить работу и установить какой-то флаг, чтобы доступ был запрещен?

Есть ли другой способ сделать это? Что мне не хватает?

Заранее спасибо.

Редактировать: Если у вас есть вопросы, что делает @ReqUser(), вот оно:

export const ReqUser = createParamDecorator((data, req): any => {
  return req.user;
});

1 Ответ

0 голосов
/ 09 ноября 2019

Неважно, я нашел решение, этот ответ очень помог. Публикация здесь на случай, если кто-то еще попадет в ту же проблему.

Я создал TwitterAuthGuard:

export class TwitterAuthGuard extends AuthGuard('twitter') {
  handleRequest(err, user, info, context) {
    return user;
  }
}

и использовал его на маршруте обратного вызова:

  @Get('twitter/callback')
  @UseGuards(TwitterAuthGuard)
  async twitterCallback(@ReqUser() socialUser: SocialAuthUser, @Res() response) {
    if (socialUser) {
      const user = await this.us.registerSocialUser(socialUser);
      if (user) {
        response.redirect(`...url`);
        return;
      }
    }
    response.redirect(SocialAuthController.authFailedUrl(LoginMethod.TWITTER));
  }

Теперь, когда Twitter вызывает маршрут обратного вызова, он попадает в метод TwitterAuthGuard handleRequest.

Если доступ предоставлен, параметр user содержит данные из профиля пользователя и передается далее по цепочке в TwitterGuard validate метод (см. Выше в вопросе).

Если доступ был запрещен, тогда user параметр равен false.

Поэтому в методе маршрута обратного вызова контроллера я получаюлибо нормализованные пользовательские данные или false в параметре user, поэтому я могу проверить, не удалось это или нет, и действовать соответствующим образом.

...