使用有效的jwt令牌为下一个js中的每个请求创建Apollo客户端,以进行客户端渲染和服务器端渲染

时间:2020-07-01 17:30:57

标签: next.js apollo

我正在努力达到以下几点。

  1. JWT身份验证
  2. 为SSR和客户端渲染创建apollo客户端。

在我的Nextjs应用程序中,我在pages文件夹中创建了一个文件_app.js,其中我有带有两个参数(组件和ctx)的静态方法getInitialProps。在此方法内部,我正在检查所有文件中的getInitialProps并返回pageProps。 pageProps =等待Component.getInitialProps(ctx), 但是,成功登录后,我无法在ctx中获取标头对象(如ctx.req或ctx.ctx.req)。 ctx.req对象只能在服务器启动后访问一次,对于其他请求,ctx.req是未定义的

我的要求是为具有有效令牌的每个请求创建一个Apollo客户端,用于SSR和客户端渲染。如果用户未登录,则应将其重定向到登录页面;如果用户登录成功,则从jwt中提取用户信息,并将其重定向到主页。

_app.js

import '../css/style.css'
import '@fortawesome/fontawesome-free/js/fontawesome';
import '@fortawesome/fontawesome-free/js/solid';
import '@fortawesome/fontawesome-free/js/regular';
import '@fortawesome/fontawesome-free/js/brands';
import '@fortawesome/fontawesome-free/css/all.css';
import "../node_modules/video-react/dist/video-react.css";
import { ApolloProvider } from '@apollo/react-hooks';

import App from 'next/app';
import client from '../lib/apollo-client'


export default class AppComponent extends App {
  static async getInitialProps({ Component, ctx}) {
    let pageProps = {};
    console.log("ctx==>",ctx)
    console.log("ctx.ctx==>",ctx.ctx) 
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }
    pageProps.query = ctx.query;
    return { 
      pageProps
    };
  }
  componentDidMount() {
    console.log("component did mount")
  }
  render() {
    console.log("render")
    const { Component, pageProps } = this.props;
    return (
        <ApolloProvider client={client}>
            <Component {...pageProps} />
        </ApolloProvider>
    );
  }
}

apollo-client.js

import { HttpLink } from 'apollo-link-http';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createUploadLink } from "apollo-upload-client";
import { setContext } from 'apollo-link-context'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'
import { AUTH_TOKEN } from '../lib/constants'

  const httpLink = new createUploadLink({
    uri: 'http://localhost:4000/'
  })
  const authLink = setContext((_, { headers }) => {
    // return the headers to the context so httpLink can read them
    const token = localStorage.getItem(AUTH_TOKEN)
    return {
      headers: {
        ...headers,
        authorization: token ? `Bearer ${token}` : "",
      }
    }
  })
  const client = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache()
  });

export default client;

login.js

import React, { Component } from 'react';
import Input from '../component/input'
import { Mutation } from 'react-apollo'
import gql from 'graphql-tag'
import Router from 'next/router'
import {AUTH_TOKEN} from '../lib/constants'
import Layout from '../component/layout'

const LOGIN = gql`
  mutation Login($email: String!,$password: String!){
    login(email: $email, password: $password)
    {
        token
        user {
            username
            email
            profilePic
            id
        }
    }
  }
`

class Login extends Component {
    handleSubmit = (e,login) => {
        e.preventDefault()
        console.log('email',e.target.email.value)
        console.log('password',e.target.password.value)
        login({
            variables: {
                email: e.target.email.value, 
                password: e.target.password.value
            }
        })
        .then((data) => {
            console.log(data)
            this._saveUserData(data.data.login.token)
        
        })
        .catch((err) => {
            console.error(err)
        })
    }
    _saveUserData = token => {
        localStorage.setItem(AUTH_TOKEN, token)
    }
    render() {
        return (
            <Layout>
                <div className = 'post-reply-container'>
                    <Mutation
                        mutation={LOGIN} 
                    >
                    {(login,{loading}) =>{
                        return <form onSubmit={e => {this.handleSubmit(e,login)}}>
                            <h1 className=""><legend><b className="d-flex justify-content-center">Login</b></legend></h1>
                            <div className="form-group row">
                                <label htmlFor="email" className="col-sm-2 col-form-label">Email:</label>
                                <Input 
                                    id = 'email'
                                    classcss='form-control form-control-lg'
                                    name = 'email'
                                    inputType = 'email'
                                    placeholder = 'Enter email'
                                />
                            </div>
                            <div className="form-group row">
                                <label htmlFor="password" className="col-sm-2 col-form-label">Password:</label>
                                <Input 
                                    id = 'password'
                                    classcss='form-control form-control-lg'
                                    name = 'password'
                                    inputType = 'password'
                                    placeholder = 'Enter password'
                                />
                            </div>
                            <button 
                                type="submit" 
                            className="btn btn-primary" 
                        >Login</button>
                    </form>
                }}
                    
                </Mutation>
                
                </div>
            </Layout>
        );
    }
}

export default Login;

mutation.js

async function login(parent, args, context, info) {
    console.log('args=>',args)
    let login = {token: null, user: null}
    let userRef = context.db.firestore().collection('users')
    await userRef.where('email', '==', args.email).get()
    .then(snapshot => {
        console.log('inside then =>')
        if (snapshot.empty) {
          throw new Error('No such user found')
        }  
        snapshot.forEach(doc => {
            console.log(doc.id, '=>', doc.data());
            const user = {...doc.data(),id:doc.id}
            const valid = bcrypt.compare(args.password, user.password)
            if (!valid) {
                throw new Error('Invalid password')
            }
            login = {
                token: jwt.sign({ userId: user.id }, constants.APP_SECRET),
                user,
            }
            return login
            });
        })
        .catch(err => {
            console.log('Error getting documents', err);
        });
    return login
}

0 个答案:

没有答案