首页 > 解决方案 > GraphQL + Redux + JWT 用户认证

问题描述

我正在尝试使用 qraphql 和 redux 设置 JWT 身份验证。目前注册功能正在工作并将新用户发布到数据库,但我似乎无法让 loadUser 功能工作。

authAction.js

const API_URL = 'https://my-server.com/api';

export const register = ({name, email, password}) => dispatch => {
    axios.post(
        API_URL, {
        query: `mutation {
            userSignup( name: "${name}", email: "${email}", password: "${password}"){
                name,
                email,
                password
            }
        }
    `,
    })
    .then(res => 
        dispatch({
        type: REGISTER_SUCCESS,
        payload: res.data.data
    }))
    .catch(err => {
        dispatch({
            type: REGISTER_FAIL
        })
    })
}



export const loadUser = (email, password) => dispatch => {

    dispatch({type: USER_LOADING})

    axios.post(
        API_URL, {
        query: `query {
            userLogin(email: "${email}", password: "${password}"){
                email,
                password,
                token
            }
        }
    `,
    })
    .then(res => dispatch({
        type: USER_LOADED,
        type: LOGIN_SUCCESS,
        payload: res.data.data
    }))
    .catch(err => {
        dispatch(retrunErrors(err.response.data, err.response.status));
        dispatch({
            type: AUTH_ERROR
        });
    });
}

这两个函数都应该返回令牌,reducer 应该将令牌设置为 localStorage。

authReducer.js

...
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
  localStorage.setItem('token', action.payload.token)
  console.log(action.payload)
    return {
       ...state,
       ...action.payload,
       isAuthenticated: true,
       isLoading: false,
    }
...

我确实使用钩子进行了登录(没有配置注册),但它都在 app.js 中,它确实需要被分解。有人告诉我,我需要将所有内容移至 redux,所以我来了。我已经翻阅了大量文档,但找不到解决方案。

FWIW,这是旧的 app.js(很长)

const API_URL = 'https://my-server.com/api';

function App() {

  const initialLoginState = {
    isLoading: false,
    userName: null,
    userToken: null,
  };

  const setUser = (token, user) => {
    if (token) {
      axios.defaults.headers.common.Authorization = `Bearer ${token}`;
    } else {
      delete axios.defaults.headers.common.Authorization;
    }

    return {type: 'LOGIN', id: user.email, token: token};
  };

  // Set a user after login or using local (AsyncStorage) token
  const setUserLocally = async (key, value) => {
    // Set token & user object
    // const items = [
    //   ['userToken', token],
    //   ['user', JSON.stringify(user)],
    // ];
    await localStorage.setItem(key, value);
  };

  const unsetUserLocally = () => {
    // Remove token
    localStorage.removeItem('userToken');
    localStorage.removeItem('user');

    return {type: 'LOGOUT'};
  };

  const loginReducer = (prevState, action) => {
    switch (action.type) {
      default: 
        return {
        ...prevState,
        userToken: action.token,
        isloading: false,
        }
      case 'RETRIEVE_TOKEN':
        return {
          ...prevState,
          userToken: action.token,
          isloading: false,
        };
      case 'LOGIN':
        return {
          ...prevState,
          userName: action.id,
          userToken: action.token,
          isloading: false,
        };
      case 'LOGOUT':
        return {
          ...prevState,
          userName: null,
          userToken: null,
          isloading: false,
        };
      case 'REGISTER':
        return {
          ...prevState,
          userName: action.id,
          userToken: action.token,
          isloading: false,
        };
    }
  };

  const [loginState, dispatch] = useReducer(loginReducer, initialLoginState);

  const auth = {
      signIn: async (userName, password) => {

        try {
          const response = await axios
            .post(
              API_URL,
              query({
                operation: 'userLogin',
                variables: {
                  email: userName,
                  password: password,
                },
                fields: ['user {name, email, role}', 'token'],
              })
            );
          let message = 'Please try again.';

          if (response.data.errors && response.data.errors.length > 0) {
            message = response.data.errors[0].message;
          } else if (response.data.data.userLogin.token !== '') {
            const token = response.data.data.userLogin.token;
            const user = response.data.data.userLogin.user;


            setUserLocally('userToken', token).then(() => {
              return setUserLocally('user', JSON.stringify(user));
              });
            dispatch(setUser(token, user));
          }
        } catch (error) {
          console.log(error);
        }
      },
      signOut: () => {
        dispatch(unsetUserLocally());
      },
      signUp: () => {
        // setUserToken('sdf');
        // setIsLoading(false);
      },
      getCurrentUser: () => {
        //return 'test'; //JSON.parse(AsyncStorage.getItem('userToken'));
        let userArr = {};
        const value = async () => {
          await localStorage.multiGet(['user', 'userToken']).then(
            (response) => {
              response.forEach((item) => {
                userArr[item[0]] = item[1];
              });
              return userArr;
              
            },
          );
        };
        return value;
       
      },
    };

  console.log(loginState.userToken)

  useEffect(() => {
    let users = async () => {
      
        let userToken;
        try {
          userToken = await localStorage.getItem('userToken');
        } catch (e) {
          console.log(e);
        }
      
        dispatch({type: 'RETRIEVE_TOKEN', token: userToken});
    };

    users();
  }, []);

  // if (loginState.isLoading === true) {
  //   return <Loading />;
  // }
  return (
    <AuthContext.Provider value={auth}>
      <Router>
      <AuthSwitcher user={loginState.userToken}/>
      </Router>
    </AuthContext.Provider>
  )
}

export default App

标签: reactjsreduxgraphqljwt

解决方案


推荐阅读