apiplatform - 反应管理员:本地存储中的令牌在重定向时为空,必须刷新页面
apiplatform - react admin: token in localstorage null on redirect, have to refresh page
我正在使用堆栈 api 平台和 React 管理员。
我的 JWT 身份验证在 api 平台上运行良好。
我尝试在我的 React 管理员后台使用它。
我遵循了这些文档:
- https://api-platform.com/docs/admin/authentication-support/
- https://marmelab.com/react-admin/doc/2.9/Authentication.html
authentification/authorization 有效,但登录成功后,我被重定向到后台,并且出现服务器通信错误,因为发送到 api 的令牌为空。
我在本地存储中看到它,如果我刷新页面,一切正常。
好像重定向成功发生在令牌存储之前。
这是我的代码:
App.js
import React from "react";
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
import authProvider from "./components/authProvider";
import parseHydraDocumentation from "@api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation";
import {
dataProvider as baseDataProvider,
fetchHydra as baseFetchHydra
} from "@api-platform/admin";
import { Redirect } from "react-router-dom";
const entrypoint = "http://localhost:8089/api";
const fetchHeaders = {
Authorization: `Bearer ${window.localStorage.getItem("token")}`
};
const fetchHydra = (url, options = {}) =>
baseFetchHydra(url, {
...options,
headers: new Headers(fetchHeaders)
});
const apiDocumentationParser = entrypoint =>
parseHydraDocumentation(entrypoint, {
headers: new Headers(fetchHeaders)
}).then(
({ api }) => ({ api }),
result => {
switch (result.status) {
case 401:
return Promise.resolve({
api: result.api,
customRoutes: [
{
props: {
path: "/",
render: () => <Redirect to={`/login`} />
}
}
]
});
default:
return Promise.reject(result);
}
}
);
const dataProvider = baseDataProvider(
entrypoint,
fetchHydra,
apiDocumentationParser
);
export default () => (
<HydraAdmin
apiDocumentationParser={apiDocumentationParser}
dataProvider={dataProvider}
authProvider={authProvider}
entrypoint={entrypoint}
>
<ResourceGuesser name="resource" />
</HydraAdmin>
);
authProvider.js
import { AUTH_LOGIN, AUTH_LOGOUT, AUTH_CHECK, AUTH_ERROR } from "react-admin";
export default (type, params) => {
if (type === AUTH_LOGIN) {
const { email, password } = params;
const request = new Request("http://localhost:8089/api/login_check", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: new Headers({ "Content-Type": "application/json" })
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ token }) => {
localStorage.setItem("token", token);
});
}
if (type === AUTH_LOGOUT) {
localStorage.removeItem("token");
return Promise.resolve();
}
if (type === AUTH_ERROR) {
console.log("AUTH_ERROR");
//localStorage.removeItem("token");
return Promise.resolve();
}
if (type === AUTH_CHECK) {
return localStorage.getItem("token")
? Promise.resolve()
: Promise.reject({ redirectTo: "/login" });
}
return Promise.resolve();
};
我不知道这是否是正确的解决方案,因为像您一样,我没有找到任何有关此问题的信息。
但对我来说,如果我在 localStorage.setItem('token', token);
之后调用 window.location.reload();
它就解决了我的问题,因为登录后,它会重新加载 admin,此时它可以识别令牌。也许这不是有史以来最干净的解决方案,但效果很好。
对了,我想,这不是HydraAdmin组件的问题,我试了经典的React Admin组件,问题依旧,所以是React Admin的问题。
我正在使用堆栈 api 平台和 React 管理员。 我的 JWT 身份验证在 api 平台上运行良好。
我尝试在我的 React 管理员后台使用它。 我遵循了这些文档:
- https://api-platform.com/docs/admin/authentication-support/
- https://marmelab.com/react-admin/doc/2.9/Authentication.html
authentification/authorization 有效,但登录成功后,我被重定向到后台,并且出现服务器通信错误,因为发送到 api 的令牌为空。
我在本地存储中看到它,如果我刷新页面,一切正常。
好像重定向成功发生在令牌存储之前。
这是我的代码:
App.js
import React from "react";
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
import authProvider from "./components/authProvider";
import parseHydraDocumentation from "@api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation";
import {
dataProvider as baseDataProvider,
fetchHydra as baseFetchHydra
} from "@api-platform/admin";
import { Redirect } from "react-router-dom";
const entrypoint = "http://localhost:8089/api";
const fetchHeaders = {
Authorization: `Bearer ${window.localStorage.getItem("token")}`
};
const fetchHydra = (url, options = {}) =>
baseFetchHydra(url, {
...options,
headers: new Headers(fetchHeaders)
});
const apiDocumentationParser = entrypoint =>
parseHydraDocumentation(entrypoint, {
headers: new Headers(fetchHeaders)
}).then(
({ api }) => ({ api }),
result => {
switch (result.status) {
case 401:
return Promise.resolve({
api: result.api,
customRoutes: [
{
props: {
path: "/",
render: () => <Redirect to={`/login`} />
}
}
]
});
default:
return Promise.reject(result);
}
}
);
const dataProvider = baseDataProvider(
entrypoint,
fetchHydra,
apiDocumentationParser
);
export default () => (
<HydraAdmin
apiDocumentationParser={apiDocumentationParser}
dataProvider={dataProvider}
authProvider={authProvider}
entrypoint={entrypoint}
>
<ResourceGuesser name="resource" />
</HydraAdmin>
);
authProvider.js
import { AUTH_LOGIN, AUTH_LOGOUT, AUTH_CHECK, AUTH_ERROR } from "react-admin";
export default (type, params) => {
if (type === AUTH_LOGIN) {
const { email, password } = params;
const request = new Request("http://localhost:8089/api/login_check", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: new Headers({ "Content-Type": "application/json" })
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ token }) => {
localStorage.setItem("token", token);
});
}
if (type === AUTH_LOGOUT) {
localStorage.removeItem("token");
return Promise.resolve();
}
if (type === AUTH_ERROR) {
console.log("AUTH_ERROR");
//localStorage.removeItem("token");
return Promise.resolve();
}
if (type === AUTH_CHECK) {
return localStorage.getItem("token")
? Promise.resolve()
: Promise.reject({ redirectTo: "/login" });
}
return Promise.resolve();
};
我不知道这是否是正确的解决方案,因为像您一样,我没有找到任何有关此问题的信息。
但对我来说,如果我在 localStorage.setItem('token', token);
之后调用 window.location.reload();
它就解决了我的问题,因为登录后,它会重新加载 admin,此时它可以识别令牌。也许这不是有史以来最干净的解决方案,但效果很好。
对了,我想,这不是HydraAdmin组件的问题,我试了经典的React Admin组件,问题依旧,所以是React Admin的问题。