我正在努力达到以下几点。
在我的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
}