无法读取未定义的 reactjs JWT 身份验证的属性“令牌”

Posted

技术标签:

【中文标题】无法读取未定义的 reactjs JWT 身份验证的属性“令牌”【英文标题】:Cannot read property 'token' of undefined reactjs JWT Authentication 【发布时间】:2021-07-06 00:22:28 【问题描述】:

有人可以帮我解决我所缺少的吗?当我尝试登录时,如果凭据正确,它应该重定向到个人资料页面,如果不是,它应该在登录按钮下方显示来自服务器 server response message screenshot 的响应消息,例如 Invalid Password ! 而不是它重定向到个人资料页面,如果登录凭据错误,则会显示此错误Error Screenshot,它应该在登录按钮下方显示错误消息,如果登录成功,它应该重定向到个人资料页面。

auth.service.js

const login = (username, password) => 
  return axios
    .post(API_URL + "signin", 
      username,
      password,
    )
    .then((response) => 
      if (response.data && response.data.data && response.data.data.token) 
        localStorage.setItem("user", JSON.stringify(response.data));
      

      return response.data;

    )
    .catch((err) => 
      console.log("An error occured: ", err);
    );
;

const logout = () => 
  localStorage.removeItem("user");
;

auth.js

import 
  REGISTER_SUCCESS,
  REGISTER_FAIL,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
  LOGOUT,
  SET_MESSAGE,
 from "./types";

import AuthService from "../services/auth.service";

export const register = (username, email, password) => (dispatch) => 
  return AuthService.register(username, email, password).then(
    (response) => 
      dispatch(
        type: REGISTER_SUCCESS,
      );

      dispatch(
        type: SET_MESSAGE,
        payload: response.data.message,
      );

      return Promise.resolve();
    ,
    (error) => 
      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString();

      dispatch(
        type: REGISTER_FAIL,
      );

      dispatch(
        type: SET_MESSAGE,
        payload: message,
      );

      return Promise.reject();
    
  );
;

export const login = (username, password) => (dispatch) => 
  return AuthService.login(username, password).then(
    (data) => 
      dispatch(
        type: LOGIN_SUCCESS,
        payload:  user: data ,
      );

      return Promise.resolve();
    ,
    (error) => 
      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString();

      dispatch(
        type: LOGIN_FAIL,
      );

      dispatch(
        type: SET_MESSAGE,
        payload: message,
      );

      return Promise.reject();
    
  );
;

export const logout = () => (dispatch) => 
  AuthService.logout();

  dispatch(
    type: LOGOUT,
  );
;

Login.js

import React,  useState, useRef  from "react";
import  useDispatch, useSelector  from "react-redux";
import  Redirect  from 'react-router-dom';

import Form from "react-validation/build/form";
import Input from "react-validation/build/input";
import CheckButton from "react-validation/build/button";

import  login  from "../actions/auth";

const required = (value) => 
  if (!value) 
    return (
      <div className="alert alert-danger" role="alert">
        This field is required!
      </div>
    );
  
;

const Login = (props) => 
  const form = useRef();
  const checkBtn = useRef();

  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);

  const  isLoggedIn  = useSelector(state => state.auth);
  const  message  = useSelector(state => state.message);

  const dispatch = useDispatch();

  const onChangeUsername = (e) => 
    const username = e.target.value;
    setUsername(username);
  ;

  const onChangePassword = (e) => 
    const password = e.target.value;
    setPassword(password);
  ;

  const handleLogin = (e) => 
    e.preventDefault();

    setLoading(true);

    form.current.validateAll();

    if (checkBtn.current.context._errors.length === 0) 
      dispatch(login(username, password))
        .then(() => 
          // props.history.push("/home");
          // window.location.reload();
        )
        .catch(() => 
          setLoading(false);
        );
     else 
      setLoading(false);
    
  ;

  if (isLoggedIn) 
    return <Redirect to="/profile" />;
  

  return (
    <div className="col-md-12">
      <div className="card card-container">
        <img
          src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
          
          className="profile-img-card"
        />

        <Form onSubmit=handleLogin ref=form>
          <div className="form-group">
            <label htmlFor="username">Username</label>
            <Input
              type="email"
              className="form-control"
              name="email"
              value=username
              onChange=onChangeUsername
              validations=[required]
            />
          </div>

          <div className="form-group">
            <label htmlFor="password">Password</label>
            <Input
              type="password"
              className="form-control"
              name="password"
              value=password
              onChange=onChangePassword
              validations=[required]
            />
          </div>

          <div className="form-group">
            <button className="btn btn-primary btn-block" disabled=loading>
              loading && (
                <span className="spinner-border spinner-border-sm"></span>
              )
              <span>Login</span>
            </button>
          </div>

          message && (
            <div className="form-group">
              <div className="alert alert-danger" role="alert">
                message
              </div>
            </div>
          )
          <CheckButton style= display: "none"  ref=checkBtn />
        </Form>
      </div>
    </div>
  );
;

export default Login;

Profile.js

import React from "react";
import  Redirect  from 'react-router-dom';
import  useSelector  from "react-redux";

const Profile = () => 
  const  user: currentUser  = useSelector((state) => state.auth);

  if (!currentUser) 
    return <Redirect to="/login" />;
  

  return (
    <div className="container">
      <header className="jumbotron">
        <h3>
          <strong>currentUser.data.userInfo.name's</strong> Profile
        </h3>
      </header>

      <p>
        <strong>Id:</strong> currentUser.data.userInfo.userId
      </p>
      <p>
        <strong>Token:</strong> currentUser.data.token
      </p>
      <p>
        <strong>Email:</strong> currentUser.data.userInfo.email
      </p>
      <p>
        <strong>Name:</strong> currentUser.data.userInfo.name
      </p>

    </div>
  );
;

export default Profile;

【问题讨论】:

【参考方案1】:

你有一些条件检查应该为你捕捉东西,但它们并不完全正确。你需要改善你的条件。

我看不到您的 Redux 状态,但我可以从错误中向后推断。您对TypeError: cannot read property 'userInfo' of undefined 的屏幕截图显示currentUser.dataundefinedProfile 组件中。所以这个检查:

if (!currentUser) 
    return <Redirect to="/login" />;

这还不够,因为您有时拥有currentUser 而没有currentUser.data。事实上,您使用的所有属性都是 currentUser.data 的子属性,因此您可以最大限度地减少从 Redux 中选择的数据量(这有助于防止不必要的重新渲染)。

const Profile = () => 
  const userData = useSelector(state => state.auth.user.data);

  if (!userData) 
    return <Redirect to="/login" />;
  

  return (
    <div className="container">
      <header className="jumbotron">
        <h3>
          <strong>userData.userInfo.name's</strong> Profile
        </h3>
      </header>

      <p>
        <strong>Id:</strong> userData.userInfo.userId
      </p>
      <p>
        <strong>Token:</strong> userData.token
      </p>
      <p>
        <strong>Email:</strong> userData.userInfo.email
      </p>
      <p>
        <strong>Name:</strong> userData.userInfo.name
      </p>

    </div>
  );
;

但我们不应该首先被重定向到Profile,所以让我们看看为什么会发生这种情况。

const  isLoggedIn  = useSelector(state => state.auth);

if (isLoggedIn) 
    return <Redirect to="/profile" />;

state.auth.isLoggedIn 属性可靠吗?你需要弄清楚为什么它会评估为true

与此同时,我们可以检查是否存在我们在 Profile 中查找的相同用户数据。

const isLoggedIn = useSelector(state => !! state.auth.user.data);

【讨论】:

以上是关于无法读取未定义的 reactjs JWT 身份验证的属性“令牌”的主要内容,如果未能解决你的问题,请参考以下文章

如何在刷新页面上存储在本地存储中的 reactjs 中使用 JWT 进行身份验证?

TypeError:无法读取未定义的属性“历史”

无法读取未定义的属性“身份验证”

无法读取未定义的属性“电子邮件”; firebase 身份验证();使用 Vuex

具有阿波罗身份验证的下一个 Js,无法读取未定义的属性“查询”

错误:无法在 reactjs 项目中读取未定义的属性(读取“地图”)\