问题
I am building an app in Reactjs. I have to make fetch call, after verifying the access_token. On signup, access_token are acquired from back-end server. But, where to store these access_token. Is there any way of making these access_token global, so that all component can access it. I have used local storage, cache and session storage, but those are not advisable. Held up in this issue for past few days, any solutions for it. Thnks in advance.
回答1:
Available options and limitations:
There are 2 types of options for storing your token:
- Web Storage API: which offers 2 mechanisms:
sessionStorage
andlocalStorage
. Data stored here will always be available to your Javascript code and cannot be accessed from the backend. Thus you will have to manually add it to your requests in a header for example. This storage is only available to your app's domain and not to sub domains. The main difference between these 2 mechanisms is in data expiry:
sessionStorage
: Data available only for a session (until the browser or tab is closed).localStorage
: Stores data with no expiration date, and gets cleared only through JavaScript, or clearing the Browser cache/Locally Stored Data
- Cookies: Automatically sent to your backend with the subsequent requests. Expiry and visibility to your Javascript code can be controlled. Can be available to your app's sub domains.
You have to consider 2 aspects when designing your authentication mechanism:
- Security: An access or identity token is a sensitive information. The main types of attacks to always consider are Cross Site Scripting (XSS) and Cross Site Request Forgery (CSRF).
- Functional requirements: Should the user stay logged in when the browser is closed? How long will be his session? etc
For security concerns, OWASP does not recommend storing sensitive data in a Web Storage. You can check their CheatSheetSeries page. You can also read this detailed article for more details.
The reason is mainly linked to the XSS vulnerability. If your frontend is not a 100% protected against XSS attacks then a malicious code can get executed in your web page and it would have access to the token. It is very difficult to be fully XSS-proof as it can be caused by one of the Javascript librairies you use.
Cookies on the other hand can be unaccessible to Javascript if they are set as HttpOnly
.
Now the problem with cookies is that they can easily make your website vulnerable to CSRF. SameSite
cookies can mitigate that type of attacks. However, older versions of browsers don't support that type of cookies so other methods are available such as the use of a state variable. It is detailed in this Auth0 documentation article.
Suggested solution:
To safely store your token, I would recommend that you use a combination of 2 cookies as described below:
A JWT token has the following structure: header.payload.signature
In general a useful information is present in the payload such as the user roles (that can be used to adapt/hide parts of the UI). So it's important to keep that part available to the Javascript code.
Once the authentication flow finished and JWT token created in the backend, the idea is to:
- Store the
header.payload
part in aSameSite
Secure
Cookie (so available only through https and still availble to the JS code) - Store the
signature
part in aSameSite
Secure
HttpOnly
Cookie - Implement a middleware in your backend to resconstruct the JWT token from those 2 cookies and put it in the header:
Authorization: Bearer your_token
You can set an expiry for the cookies to meet your app's requirements.
This idea was suggested and very well described in this article by Peter Locke.
回答2:
Michael Washburn has a really good article on how to persist your state with redux, here on his webpage
In the article, he has a link to a very descriptive video tutorial created by Dan Abramov, one of the co-authors of Redux, I followed along with him to add it to my project. Here is the code I used to make it work:
store.js
import { createStore, combineReducers } from "redux";
import { UserReducer, CopyReducer } from "../reducers";
import { loadState, saveState } from "../utils/localStorage";
export const giveMeStore = () => {
const reducers = combineReducers({
copy: CopyReducer,
user: UserReducer
});
const persistedState = loadState();
const store = createStore(reducers, persistedState);
//user contains the TOKEN
store.subscribe(() => {
saveState({
user: store.getState().user
});
});
return store;
};
localStorage.js
export const loadState = () => {
try {
const serializedState = localStorage.getItem("state");
if (serializedState === null) {
return undefined;
}
return JSON.parse(serializedState);
} catch (err) {
return undefined;
}
};
export const saveState = state => {
try {
const serializedState = JSON.stringify(state);
localStorage.setItem("state", serializedState);
} catch (err) {
//ignoring write erros
}
};
and add the store to the provider:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { giveMeStore } from "./store.js";
const Root = () => {
return (
<Provider store={giveMeStore()}>
//... your components
//...
</Provider>
);
};
ReactDOM.render(<Root />, document.querySelector("#root"));
来源:https://stackoverflow.com/questions/48983708/where-to-store-access-token-in-react-js