redux POST http://localhost:3000/api/v1/stories 401(未经授权)

fxnxkyjh  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(89)

嗨,我是新的redux和身份验证。我正在创建一个React/redux应用程序,用户可以登录,并能够通过提交一个表单添加一个故事。我能够登录,但当我到达故事创建页面,我点击提交,我得到一个POST http://localhost:3000/api/v1/stories 401 (Unauthorized)错误。我正在使用一个API登录,该API在登录时提供一个令牌。然后我将用户名和令牌保存到sessionstorage。但我如何修复这个错误?
App.js

import './App.scss';
import Login from './components/Login';
import { Router, Switch, Route, NavLink } from 'react-router-dom';
import PrivateRoute from './utils/PrivateRoute';
import CreateStory from './components/CreateStory';
import history from './utils/history';

function App() {

  return (
    <div className="App">

      <Router history={history}>
        <Switch>
          <Route exact path="/" component={Login} />
          <PrivateRoute path="/user" component={CreateStory}/>

        </Switch>
      </Router>
    </div>
  );
}

export default App;

字符串
PrivateRoute.js

import { useSelector } from 'react-redux'
 
// handle the private routes
function PrivateRoute({ component: Component, ...rest }) {

  const getToken = useSelector((state)=> state.loginReducer.token)
  console.log(getToken)
  return (
    <Route
      {...rest}
      render={(props) => getToken ? <Component {...props} /> : <Redirect to={{ pathname: '/', state: { from: props.location } }} />}
    />
  )
}
 
export default PrivateRoute;


CreateStory.js

import React, { useState } from 'react'
import { createStory } from '../redux/actions'
import { useDispatch } from "react-redux";

const CreateStory = () => {

    const [summary, setSummary] = useState("");
    const [description, setDescription] = useState("");
    const [type, setType] = useState("");
    const [complexity, setcomplexity] = useState("");

    const usedispatch = useDispatch();
    const userCreateStory = (summary, description, type, complexity) => usedispatch(createStory({
                                                                                    'summary': summary,
                                                                                    'description': description,
                                                                                    'type': type,
                                                                                    'complexity': complexity 
                                                                                }));

    const handleSummaryChange = e => {
        setSummary(e.target.value)
    }  
    
    const handleDescriptionChange = e => {
        setDescription(e.target.value)
    }

    const handleTypeChange = e => {
        setType(e.target.value)
    }

    const handleComplexityChange = e => {
        setcomplexity(e.target.value)
    }

    const handleSubmit = e => {
        e.preventDefault();
        userCreateStory('a','b','c','d')
      //  setTimeout(()=> history.push("/user"), 1000 );
    }

    return (
        <div>
            <form className='create-story-form'>
                <label for="summary">Summary:</label>
                <input name="summary" type='text' onChange={handleSummaryChange}/>
                <label for="desc">Description:</label>
                <textarea name="desc" type='text' onChange={handleDescriptionChange}/>
                <label for="type">Type:</label>
                <select name="type">
                    <option value="enhancement">Enchancement</option>
                    <option value="bugfix">Bugfix</option>
                    <option value="development">Development</option>
                    <option value="qa">QA</option>
                </select>
                <label for="complexity">Complexity:</label>
                <select name="complexity">
                    <option value="Low">Low</option>
                    <option value="Mid">Mid</option>
                    <option value="High">High</option>
                </select>
                <label for="time">Estimated time for completion:</label>
                <input name="time" type='text' />
                <label for="cost">Cost:</label>
                <input name="cost" type='number' />
                <button onClick={handleSubmit}>Submit</button>
            </form>
        </div>
    )
}

export default CreateStory;


Login.js

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { login, roleChange } from '../redux/actions' //OUR ACTIONS
import { useSelector } from 'react-redux'
import history from '../utils/history';
import { withRouter } from 'react-router-dom';

const Login = () => {

    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");

    const usedispatch = useDispatch();
    const userLogin = (email, password) => usedispatch(login({'email': email, 'password': password }));
    const switchToAdmin = () => usedispatch(roleChange('admin'));
    const switchToUser = () => usedispatch(roleChange('user'));
    const currentRole = useSelector((state)=> state.loginReducer.role)

    const handleRoleChange = e => {
        e.preventDefault();
        if(currentRole === 'user')
            switchToAdmin();
        else if(currentRole === 'admin' )
            switchToUser()
    }
    
    const handleEmailChange = e => {
        setEmail(e.target.value)
    }

    const handlePasswordChange = e => {
        setPassword(e.target.value)
    }

    const handleSubmit = e => {
        e.preventDefault();
        userLogin(email, password)
        setTimeout(()=> history.push("/user"), 1000 );
    }

    const disabled = () => {
        return email === "" || password === ""
    }

   

    return (
        <div>
            <form className='login-form'>
                <input type='email' name='email' placeholder='Email' onChange={handleEmailChange}/>
                <input type='password' name='password' placeholder='Password' onChange={handlePasswordChange}/>
                <button type='submit' disabled={disabled()} onClick={handleSubmit}>Login</button>
            </form>
            <button onClick={handleRoleChange}>Switch to {currentRole === 'user' ? 'admin' : 'user'}</button>
        </div>
    )
}

export default withRouter(Login);


actionTypes.js

export const SET_LOGIN_STATE = "SET_LOGIN_STATE"
export const SET_ROLE_STATE = "SET_ROLE_STATE"
export const CREATE_STORY = "CREATE_STORY"


initialState.js:

import { getToken } from '../utils/Common'

export const initialState = {
    isLoggedIn: false,
    userId: '',
    role: 'user',
    token: getToken,
    data: '',
  };


reducers.js

import { initialState } from './initialState';
import * as t from './actionTypes';

export const loginReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.SET_ROLE_STATE:
      return {
        ...state,
        role: action.payload,
      };
    case t.SET_LOGIN_STATE:
      return {
        ...state,
        ...action.payload, // this is what we expect to get back from API call and login page input
        isLoggedIn: true, // we set this as true on login
      };
    default:
      return state;
  } 
};

export const storyReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.CREATE_STORY:
      return {
        ...state,
        role: action.payload,
      };
    default:
      return state;
  } 
}


actions.js:

import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';

// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
  return {
    type: t.SET_LOGIN_STATE,
    payload: loginData, //{ ...json, userId: email }
  };
};

const setStoryState = (storyData) => {
    return {
      type: t.CREATE_STORY,
      payload: storyData,
    };
  };

export const login = (loginInput) => { //our login action
    const { email, password } = loginInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/signin', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(loginInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
           // console.log(json)
            dispatch(setLoginState({ ...json, userId: email })); // our action is called here with object as parameter, this is our payload
            //we appended json object to our state
            //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
            setUserSession(json.token, json.lastName)
        })
        .catch((err) => {
          alert('Login Failed', 'Some error occured, please retry');
          console.log(err);
        });
    };
};

export const roleChange = role => {
    return {
        type: t.SET_ROLE_STATE,
        payload: role
      };
}

/**
 * story input:
{
  "summary": "string",
  "description": "string",
  "type": "string",
  "complexity": "string"
}
 */

export const createStory = storyInput => {
    const { summary, description, type, complexity } = storyInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/stories', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(storyInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
            console.log(json)
            // dispatch(setStoryState({  // our action is called here with object as parameter, this is our payload
            //     summary: summary,
            //     description: description,
            //     type: type,
            //     complexity: complexity
            // })); // our action is called here
        //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
        })
        .catch((err) => {
          alert('Some error occured, please retry');
          console.log(err);
        });
    };
}


Common.js

// return the user data from the session storage
export const getUser = () => {
    const userStr = sessionStorage.getItem('user');
    if (userStr) return JSON.parse(userStr);
    else return null;
}
   
// return the token from the session storage
export const getToken = () => {
    return sessionStorage.getItem('token') || null;
}
   
// remove the token and user from the session storage
export const removeUserSession = () => {
    sessionStorage.removeItem('token');
    sessionStorage.removeItem('user');
}
   
// set the token and user from the session storage
export const setUserSession = (token, user) => {
    sessionStorage.setItem('token', token);
    sessionStorage.setItem('user', JSON.stringify(user));
}

qni6mghb

qni6mghb1#

您必须将auth tokensessionStorage传递到您要将故事发布到的API的头部:-

const token = sessionStorage.getItem('token'); //Add this line

return fetch('http://localhost:3000/api/v1/stories', {
    method: 'POST',
    headers: {  
      Accept: 'application/json',
      'Content-Type': 'application/json',
       Authorization: `Bearer ${token}` //Add this line
    },
    body: JSON.stringify(storyInput),
  })

字符串

20jt8wwn

20jt8wwn2#

在我的情况下,GET,PUT和POST工作,但唯一的问题是与POST。我也尝试通过中间件。但不去中间件,直接返回401状态代码。
然后,我只需更改端点的名称,它就可以为我工作。

相关问题