【问题标题】:NodeJS ReactJS Redux displays undefined for token api tokenNodeJS ReactJS Redux 显示未定义的令牌 api 令牌
【发布时间】:2023-01-21 21:47:22
【问题描述】:

请在应用程序中使用 NodeJS ReactJS Redux 和 JWT,我在 reactjs 前端获取 expiresIn 和令牌时遇到问题,当我在 NodeJS 控制器上控制台记录令牌时,它完美地显示令牌和所有内容,但它指向 jwt。 verify() with error JsonWebTokenError: jwt malformed 但在 ReactJS 前端,它显示令牌的 payLoad userData 部分,并为 expiresIn 和令牌显示未定义。

正如你在 Redux authSlice 类中看到的那样,我在其中为令牌、过期和用户数据设置了 localStorage 项,但是当我尝试在另一个页面中获取 localStorage 项时,我只能获取 userData 有效负载,但令牌和过期未定义。我不知道这里出了什么问题,因为 NodeJS 发送了真实的令牌,因为我可以从 NodeJS 和 ThunderClient API 的控制台获取令牌,当我在 VS Code 中使用 ThunderClient 测试 api 时也给出了 200 OK。

我担心的是 ThunderClient 显示 200 OK 并返回 Token、expiresIn 和 userData 完整且一切完美,NodeJS 控制台在控制台上显示正确的信息但给出了 JsonWebTokenError: jwt malformed 并且在 ReactJS 前端,我从 api 发送的令牌中获得了 userData 但是accessToken 和 expiresIn 丢失了,即在 JWT 加密的 3 个字符串中,我只得到了 Payload,即 userData。

请问我做错了什么,我该如何解决这个问题?

*******************NODEJS

=jwtHelper.js

exports.extractToken = (req) => {
    if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
        return req.headers.authorization.split(' ')[1];
    } else if (req.query && req.query.token) {
        return req.query.token;
    }
    return null;
}



=jwtVerify.js

module.exports = function (req, res, next) {
    try {
        const token = extractToken(req);

        if (token == null) {
            return res.status(StatusCodes.UNAUTHORIZED).send("Unauthorized");
        }
        
        jwt.verify(token, common_helper.getJWTAccessToken(), {}, (err, user) => {
            if (err) {
                console.log(err);
                return res.status(StatusCodes.FORBIDDEN).send("Invalid user");
            }
            req.user = user["userData"];
            next();
        });
    } catch (e) {
        next(e);
    }
};

=Login (Controller)

const token = jwt.sign({userData}, common_helper.getJWTAccessToken(), {
          algorithm: 'HS256',
          expiresIn: common_helper.getJWTExpiryTime(),
   });

res.status(StatusCodes.OK).send({"expires_in": common_helper.getJWTExpiryTime(),"access_token":token,"token_type": "bearer","userData":userData});

console.log(`The token is ${token}`) // This displays the ciper token
console.log(`The secret_token is ${common_helper.getJWTExpiryTime()}`) //this displays the real secret key



*******************REACTJS

=Redux Slice . Note that the localStorage is set here

import { createSlice, PayloadAction } from "@reduxjs/toolkit";

interface IAuthToken {
    isAuthenticated?:boolean,
    jwtToken: any;
    expiryDate: any;
    errorMessage?:string;
    userData?:any;
    notverified?: string;
}

const initialState: IAuthToken = {
    jwtToken: undefined,
    expiryDate: undefined,
    errorMessage:'',
    isAuthenticated:false,
    userData:undefined,
    notverified: undefined,
};

const authSlice = createSlice({
    name: "auth",
    initialState,
    reducers: {
        setJWTToken: (state, _action: PayloadAction<IAuthToken>) => {
            state.jwtToken = _action.payload.jwtToken;
            state.expiryDate = _action.payload.expiryDate;
            state.userData=_action.payload.userData;
            localStorage.setItem('token', state.jwtToken);
            //localStorage.setItem('token', JSON.stringify(state.jwtToken));
            localStorage.setItem('expire', state.expiryDate);
            //localStorage.setItem('expire', JSON.stringify(state.expiryDate));
            if(state.userData)
            localStorage.setItem('userData',JSON.stringify(state.userData));
            state.isAuthenticated = true;
            state.notverified = _action.payload.notverified;
           
        },
        removeJWTToken: (state) => {
            localStorage.clear();
            state.jwtToken = '';
            state.expiryDate=undefined;
            state.isAuthenticated = false;
        },
        setError: (state, _action: PayloadAction<string>) => {
            state.errorMessage = _action.payload;
        },
    },
});

export const { setJWTToken, removeJWTToken,setError } = authSlice.actions;

export default authSlice.reducer;


=ReactJS Login

Axios.post(`${baseURL}/signin`, { username: formik.values.username,  password: formik.values.password})
            .then((response) => {
              if(response.data.notverified)
              {
                setSubmitting("");
                navigate("/needemailconfirmation", { replace: true });                
              }
                           
                setSubmitting("");               
                console.log(response.data)
                dispatch(setJWTToken(response.data));                                            
                navigate("/dashboardd", { replace: true });

=authAction

export const signIn = (email, password) => {
  return (dispatch) => {
    axios
      .post(`${url}/signin`, { email, password })
      .then((token) => {
        localStorage.setItem("token", token.data);

        dispatch({
          type: "SIGN_IN",
          token: token.data,
        });
      })
      .catch((error) => {
        console.log(error.response);

        toast.error(error.response?.data, {
          position: toast.POSITION.BOTTOM_RIGHT,
        });
      });
  };
};

=authReducer

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case "SIGN_IN":
    case "SIGN_UP":
    case "USER_LOADED":
      toast("Welcome...", {
        position: toast.POSITION.BOTTOM_RIGHT,
      });
      const user = jwtDecode(action.token); 
      return {
        ...initialState,
        token: action.token,
        name: user.name,
        email: user.email,
        _id: user._id,
      };
    case "SIGN_OUT":
      localStorage.removeItem("token");
      toast("Goodbye...", {
        position: toast.POSITION.BOTTOM_RIGHT,
      });
      return {
        token: null,
        name: null,
        email: null,
        _id: null,
      };
    default:
      return state;
  }
};

在我的 ReactJS 前端,从 NodeJS api 发送的令牌中,我能够从令牌中获取 userData 有效负载,但由于我不知道的原因,我无法获取令牌和 expiresIn。

谢谢

You can find the token details from the browser inspect here where I got userData payload but got undefines for accesstoken and expiresIn

【问题讨论】:

    标签: node.js reactjs redux jwt


    【解决方案1】:

    在我上面的问题中,我指出在调试代码时没有在我的 ReactJS frontendm 中获取令牌值我在成功登录后立即在登录页面设置了 localStorage,并且我使用了 localStorage getItem() 来获取我的值Redux 切片,但仍然存在的问题是我的 ReactJS 前端不允许我进入仪表板,因为它的行为就像未设置值一样,即中间件无法获取值,并且路由允许用户导航到仪表板尽管已设置令牌,但仍在将导航弹回登录页面,我可以在浏览器检查中获取令牌以确保已设置,但 Auth Middleware 未获取它。请参阅下面的代码:

    ******************ReactJS
    
    ===Login.js   
    
       //call the api
            Axios.post(`${baseURL}/signin`, { username: formik.values.username,  password: formik.values.password})
                .then((response) => {
                  if(response.data.notverified)
                  {
                    setSubmitting("");
                    navigate("/needemailconfirmation", { replace: true });                
                  }
                               
                    setSubmitting("");                
                    console.log(response.data)
                    if(response.data.access_token){
                      dispatch(setJWTToken(response.data));  
                      localStorage.setItem('token', JSON.stringify(response.data.access_token));
              
                      localStorage.setItem('expire', JSON.stringify(response.data.expires_in));  
                               
                      localStorage.setItem('userData', JSON.stringify(response.data.userData));                            
                    }
                
                    navigate("/dashboardd", { replace: true });             
          
          }) .catch((error) =>{
            setSubmitting("");
              //console.log(error.data);
              setErrorMsg("Invalid Login Credentials Supplied.");
              //alert("Invalid Login Credentials Supplied, Error : <br>" + error.data);
          });
          }
    
    ====Redux Slice Auth File
    
    interface IAuthToken {
        isAuthenticated?:boolean,
        jwtToken: any;
        expiryDate: any;
        errorMessage?:string;
        userData?:any;
        notverified?: string;
    }
    
    const initialState: IAuthToken = {
        jwtToken: undefined,
        expiryDate: undefined,
        errorMessage:'',
        isAuthenticated:false,
        userData:undefined,
        notverified: undefined,
    };
    
    const authSlice = createSlice({
        name: "auth",
        initialState,
        reducers: {
            setJWTToken: (state, _action: PayloadAction<IAuthToken>) => {                   state.jwtToken = localStorage.getItem("token");
                state.expiryDate = localStorage.getItem("expire");
                state.userData = localStorage.getItem("userData");
               
                if(localStorage.getItem("userData"))           
                state.isAuthenticated = true;
                state.notverified = '';
               
            },
            removeJWTToken: (state) => {
                localStorage.clear();
                state.jwtToken = '';
                state.expiryDate=undefined;
                state.isAuthenticated = false;
            },
            setError: (state, _action: PayloadAction<string>) => {
                state.errorMessage = _action.payload;
            },
        },
    });
    
    export const { setJWTToken, removeJWTToken,setError } = authSlice.actions;
    
    export default authSlice.reducer;
    
    ======AuthenticatedRoute.js : this is used in bouncing user back if they token is not found
    
    const AuthenticatedRoute: FC<{ element: any }> = ({ element }) => {
        const token = localStorage.getItem('token');
        const expire = localStorage.getItem('expire');
        
        const now = Date.now();
        if (token && expire && parseInt(expire) > parseInt(now.toString())) {
            return element;
        } else {
            return <Navigate to="/" replace />
        }
    };
    
    export default AuthenticatedRoute;
    
    ===========My React Router Dom
    
    <Route path="/dashboardd"  element={<dashboard />}></Route>
    
    <Route path="/checkpoint" element={<AuthenticatedRoute element={<CheckpointList />} />}></Route>
    
    <Route path="/vendour" element={<AuthenticatedRoute element={<VendourList />} />}></Route>
    
    

    React Router Dom 路径工作正常,但只是如果我将 AuthenticatedRoute 放到仪表板路由中,它不允许我进入,因为 AuthenticatedRoute 没有看到我认为的令牌但是当我在仪表板中控制令牌时,如果我删除 AuthenticatedRoute,值是那里。

    使用 React Router Dom,我正在调试这段代码并从仪表板中删除 AuthenticatedRoute 中间件,我能够导航到仪表板并获取令牌和 expiresIn 的 localStorage 值,但重点仍然是当我将 AuthenticatedRoute 中间件放在仪表板路由中时,AuthenticatedRoute 会将我弹回到登录页面,这意味着它找不到令牌。

    请帮忙

    【讨论】:

      猜你喜欢
      • 2019-12-24
      • 2017-06-12
      • 2017-04-14
      • 1970-01-01
      • 2021-07-02
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 2019-01-13
      相关资源
      最近更新 更多