简体   繁体   中英

How to add bearer token in the API called in getServerSideProps() in nextjs?

Intro

I am developing an login application using Nextjs on frontend and springboot on backend.

Problem

I am able to login from the frontend which calls the loginAPI named /authenticate developed in springboot and it is successfully returning the authToken .After login I got redirects to home ( /allcoupons ) page.

In login, I am passing the value of token as response.data like this

 const handleSubmit = async (e) => {
    // e.preventDefault();

    let requestbody = {
      username: credentials.username,
      password: credentials.password,
    };

    try {
      const response = await axios({
        method: "post",
        headers: {},
        url: "http://localhost:8081/authenticate",
        data: requestbody,
      });

      //console.log("credentials for login = ", credentials);
      //console.log("response from api = ", response);
      if (response.status === 200) {
        router.push(
          {
            pathname: "/allcoupons",
            query: { auth: JSON.stringify(response.data) },
          },
          undefined,
          {
            shallow: true
          }
        );

      } else alert("invalid credentials");
    } catch (error) {
      setTimeout(() => {
        setShowAlert(true);
      }, 2000);
      setShowAlert(false);
    }
  };

Then I redirects to /allcoupons component In this component I am using getServerSideProps() . I am able to access the authtoken value from context.query.auth but now I am unable to send this authtoken value as bearer token with another API /allcoupons in the headers.

home.js

import React, { Fragment, useState, useEffect } from "react";
import { useRouter } from "next/router";
import Footer from "./components/footer";
import { Alert } from "flowbite-react";
import axios from "axios";



const Allcoupons = ({ datafromAPI }) => {
  const router = useRouter();

  //console.log("datafromAPI in components = ", datafromAPI.coupons)
  //let data = datafromAPI.coupons;
const val = router.query.auth ? JSON.parse(router.query.auth) : {};
  console.log("authtoken form login = ", val);

  const [showModal, setShowModal] = useState(false);
  .
  .


  return (
    <>
      .
      .
      .
    </>
);
};

export async function getServerSideProps(context) {
  //Fetch data from get API
  //console.log("context = ", context.query.auth);
  const token = context.query.auth;
  console.log("token = ",context.query.auth)
  const res = await axios.get(
    `http://localhost:8081/couponstore/v1.0/coupons`,
     //using like this
    { headers: { Authorization: `Bearer ${token}` } }
  );
  const datafromAPI = res.data;
  console.log("data from API server = ",datafromAPI);

  return { props: { datafromAPI } };
}

Observation

But as soon as I redirects to this page, it endpoint change from /allcoupons to /allcoupons?auth={authtokenvalue} .

Logs/StackTrace

Also this log comes in the terminal

token =  "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcnVuYWJoIiwiZXhwIjoxNjY0NTQwODYwLCJpYXQiOjE2NjQ1MzM2NjB9.Ib3X-6TMyQ3YfoGz-PuS4hehzuHq-N6XHwzLF6cXD2U"
error - [AxiosError: Request failed with status code 403] {
  code: 'ERR_BAD_REQUEST',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [Function: httpAdapter],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function] },
    validateStatus: [Function: validateStatus],
    headers: {
      Accept: 'application/json, text/plain, */*',
      Authorization: 'Bearer "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcnVuYWJoIiwiZXhwIjoxNjY0NTQwODYwLCJpYXQiOjE2NjQ1MzM2NjB9.Ib3X-6TMyQ3YfoGz-PuS4hehzuHq-N6XHwzLF6cXD2U"',
      'User-Agent': 'axios/0.27.2'
    },
    method: 'get',
    url: 'http://localhost:8081/couponstore/v1.0/coupons',
    data: undefined
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: false,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: 0,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: false,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'localhost',
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [Circular *1],
      write: [Function: writeAfterFIN],
      [Symbol(async_id_symbol)]: 285969,
      [Symbol(kHandle)]: [TCP],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 60,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'GET /couponstore/v1.0/coupons HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Authorization: Bearer "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcnVuYWJoIiwiZXhwIjoxNjY0NTQwODYwLCJpYXQiOjE2NjQ1MzM2NjB9.Ib3X-6TMyQ3YfoGz-PuS4hehzuHq-N6XHwzLF6cXD2U"\r\n' +
      'User-Agent: axios/0.27.2\r\n' +
      'Host: localhost:8081\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: nop],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 80,
      protocol: 'http:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype],
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'GET',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/couponstore/v1.0/coupons',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [Socket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 403,
      statusMessage: '',
      client: [Socket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'http://localhost:8081/couponstore/v1.0/coupons',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 18,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'localhost',
    protocol: 'http:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 0,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'http://localhost:8081/couponstore/v1.0/coupons',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      authorization: [Array],
      'user-agent': [Array],
      host: [Array]
    },
    [Symbol(kUniqueHeaders)]: null
  },
  response: {
    status: 403,
    statusText: '',
    headers: {
      'x-content-type-options': 'nosniff',
      'x-xss-protection': '1; mode=block',
      'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
      pragma: 'no-cache',
      expires: '0',
      'x-frame-options': 'DENY',
      'content-length': '0',
      date: 'Fri, 30 Sep 2022 10:27:40 GMT',
      connection: 'close'
    },
    config: {
      transitional: [Object],
      adapter: [Function: httpAdapter],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [Object],
      method: 'get',
      url: 'http://localhost:8081/couponstore/v1.0/coupons',
      data: undefined
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [Socket],
      _header: 'GET /couponstore/v1.0/coupons HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Authorization: Bearer "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcnVuYWJoIiwiZXhwIjoxNjY0NTQwODYwLCJpYXQiOjE2NjQ1MzM2NjB9.Ib3X-6TMyQ3YfoGz-PuS4hehzuHq-N6XHwzLF6cXD2U"\r\n' +
        'User-Agent: axios/0.27.2\r\n' +
        'Host: localhost:8081\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/couponstore/v1.0/coupons',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'localhost',
      protocol: 'http:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(kUniqueHeaders)]: null
    },
    data: ''
  },
  page: '/allcoupons'
}

Whats the mistake here??

This how do usually when I create react apps

  1. I create a global context
import { createContext } from "react";
import { GlobalContextType } from "../types";

const defaultValue: GlobalContextType = {
   dispatch: () => {},
   state: {
        user: { authToken: "", username: "" }
        
    },
};
export const GlobalContext = createContext(defaultValue);
  1. create a hook for my global context
import { useContext } from "react";
import { GlobalContext } from "../contexts";

export function useGlobalContext () {

    const context = useContext(GlobalContext)
    if (!context) throw new Error("Missing Context - Global context");

    return context;
}
  1. Create state reducer hook
import { Dispatch, useMemo, useReducer } from "react";
import {
   
    GlobalContextActions,
    GlobalContextState,
   
} from "../types";


export function globalContextReducer(
    state: GlobalContextState,
    action: ReducerAction<GlobalContextActions>
): GlobalContextState {
    switch (action.type) {
        case GlobalContextActions.setUser:
            return {
                ...state,
                user: action.payload
            };
        

        default:
            return state;
    }
}
export function useGlobalContextReducer(reducer = globalContextReducer) {
    const [state, dispatch] = useReducer(reducer, {
        user : {authToken: "", username: ""}
    });
  

    return useMemo(() => {
        return {
            dispatch,
            state,
        };
    }, [d, state]);
}
  1. Wrapped the whole App with my global context
import { GlobalContext } from "../src/contexts";
import { useGlobalContextReducer } from "../src/hooks/use-global-context-reducer";

export default function MyApp(props: MyAppProps) {
    const { Component pageProps } = props;
    const globalContextReducer = useGlobalContextReducer();
    return (       
          <GlobalContext.Provider value={globalContextReducer}>
            <Component {...pageProps} />   
          </GlobalContext.Provider>
    );
}

this just my setup

then in my login page

import {GlobalContextActions, useGlobalContext} from "../../context"
import {Routes} from "../routes"

function Login() {
    const { dispatch} = useGlobalContext();
    const router = useRouter();
    const [form, updateForm] = useState({
        email: "",
        password: "",
    });

   

    const onFieldChange = (event: ChangeEvent<HTMLInputElement>) => {
        const { target } = event;
        const { id, value } = target;
        updateForm((current) => ({ ...current, [id]: value }));
    };

    const isLoginDisabled = !validateEmail(form.email) || !form.password;

    const onLogin = async () => {
        const dataService = container.resolve(DataService);
        const result = await dataService.getLoginData(form.email, form.password);
        if (result.error) {
            return dispatchError(result?.errorMessage as string);
        }
        useGlobalContextReducer({action:GlobalContextActions.setUser, payload: result.data});
        router.push(Routes.home);
    };
    return (
        <Box>
            <form action="" onSubmit={(event) => event?.preventDefault()}>
                <TextField
                    id="email"
                    label={"email"}
                    variant="standard"
                    required
                    value={form.email}
                    onChange={onFieldChange}
                    type="email"
                    fullWidth
                    data-testid="email"
                />
                <TextField
                    id="password"
                    label={"password"}
                    variant="standard"
                    type="password"
                    value={form.password}
                    required
                    fullWidth
                    onChange={onFieldChange}
                    data-testid="password"
                />
                <Button type="submit" variant="contained" disabled={isLoginDisabled} onClick={onLogin}>
                    Login
                </Button>
            </form>
        </Box>
    );
}

export default Login;

and this how I use the global state

function MyPage() {
   const {state} = useGlobalContext

  return (<div>{JSON.stringinfy(state)}</div>)

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM