akveo / nebular

:boom: Customizable Angular UI Library based on Eva Design System :new_moon_with_face::sparkles:Dark Mode
https://akveo.github.io/nebular
MIT License
8.06k stars 1.51k forks source link

auntenticacion with graphql #2178

Open jorgnv opened 4 years ago

jorgnv commented 4 years ago

I'm trying to authenticate with graphql, the server returns my token but NbAuth isn't taking it, I guess because of the kind of response graphql sends

import { NbPasswordAuthStrategy, NbAuthJWTToken } from '@nebular/auth';
import { environment } from '../../environments/environment';

export const socialLinks = [
  {
    url: 'https://github.com/akveo/nebular',
    target: '_blank',
    icon: 'github',
  },
  {
    url: 'https://www.facebook.com/akveo/',
    target: '_blank',
    icon: 'facebook',
  },
  {
    url: 'https://twitter.com/akveo_inc',
    target: '_blank',
    icon: 'twitter',
  },
];

export const authOptions = {
  strategies: [
    NbPasswordAuthStrategy.setup({
      name: 'email',
      baseEndpoint: environment.apiUrl,
      token: {
        class: NbAuthJWTToken,
        key: 'token',
      },
      login: {
        endpoint: '/',
        method: 'post',
      },
      register: {
        endpoint: '/auth/sign-up',
        method: 'post',
      },
      logout: {
        endpoint: '/auth/sign-out',
        method: 'post',
      },
      requestPass: {
        endpoint: '/auth/request-pass',
        method: 'post',
      },
      resetPass: {
        endpoint: '/auth/reset-pass',
        method: 'post',
      },
    }),
  ],
  forms: {
    login: {
      socialLinks: socialLinks,
    },
    register: {
      socialLinks: socialLinks,
    },
  },
};
login(): void {
     this.user = this.loginForm.value;
     this.errors = []
     this.messages = []
     this.submitted = true
     const data = {
       variables: {
         input: {
           email: email,
           passwordHash: pass
         }
       },
       query: 'mutation login($input: LoginInput) { login(input: $input){ token } }',
     }
     this.service.authenticate(this.strategy, data).subscribe((result: NbAuthResult) => {
       this.submitted = false
       console.log(result)
       if (result.isSuccess()) {
         this.messages = result.getMessages()
       } else {
         this.errors = result.getErrors()
       }

       const redirect = result.getRedirect()
       if (redirect) {
         setTimeout(() => {
           return this.router.navigateByUrl(redirect)
         }, this.redirectDelay)
       }
       this.cd.detectChanges()
     })
   }

Graphql return:

{
"data":{
  "login":{      "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiYW05eVoyNTJRR2R0WVdsc0xtTnZiUT09IiwiaWF0IjoxNTc5NDA3NjIyLCJleHAiOjE1ODAwMTI0MjJ9.adP0HmrGJPOgtTMudDGX81-E1ScGooe-XRGA_ywnKwI"
    }
  }
}
scorpion112345 commented 4 years ago

You need to implement your own Strategy for example in graphql-strategy.ts put this

export class GraphqlAuthStrategy extends NbAuthStrategy {

  protected defaultOptions: NbPasswordAuthStrategyOptions = passwordStrategyOptions;
  static setup(options: NbPasswordAuthStrategyOptions): [NbAuthStrategyClass, NbPasswordAuthStrategyOptions] {
    return [GraphqlAuthStrategy, options];
  }

  constructor(private apollo: Apollo, protected http: HttpClient) {
    super();
  }

  authenticate(data?: any): Observable<NbAuthResult> {
    const module = 'login';
    const requireValidToken = this.getOption(`${module}.requireValidToken`);
    return this.apollo
      .mutate<{ signin: any }>({
        mutation: userLogin, variables: data,
      })
      .pipe(
        map((res) => {
          const response = { data: { ...res.data.signin } }
          return new NbAuthResult(
            true,
            response,
            this.getOption(`${module}.redirect.success`),
            [],
            this.getOption('messages.getter')(module, res, this.options),
            this.createToken(this.getOption('token.getter')(module, response, this.options), requireValidToken));
        }),
        catchError((res) => {
          return this.handleResponseError(res, module);
        }),
      );
  }

....
}

The full code are on their repo https://github.com/akveo/nebular/blob/master/src/framework/auth/strategies/password/password-strategy.ts so you need to implement the other methods and chaged it as you want

After that dont forget to add the startegy on your module like this

  ...NbAuthModule.forRoot({
    strategies: [
      GraphqlAuthStrategy.setup({
        name: 'email',
        token: {
          class: NbAuthJWTToken,
          key: 'token', // this parameter tells where to look for the token
          getter: (module: string, res: any, options: NbPasswordAuthStrategyOptions) => getDeepFromObject(
            res.data,
            options.token.key,
          ),
        },
      }),
    ],
  }).providers

and also in the providers

export class CoreModule {

  static forRoot(): ModuleWithProviders<CoreModule> {
    return {
      ngModule: CoreModule,
      providers: [
        ...NB_CORE_PROVIDERS,
        GraphqlAuthStrategy
      ],
    };
  }
}

So finally on your login component yo can do

  async login() {
    let data = {
      input: {
        email:"123",
        password:"test@gmail.com"
      }
    };
    this.service.authenticate(this.strategy, data).subscribe((result: NbAuthResult) => {

      if (result.isSuccess()) {
        const redirect = result.getRedirect()
        this.router.navigateByUrl(redirect)
      }

    })
  }

my login mutation

    mutation signin($input: SigninInput!) {
        signin(signinInput: $input) {
            token
        }
    }