0

我尝试创建自定义钩子来调用 DataProvidergetOne()方法,以根据登录后从 authProvider 获得的用户名获取权限,但是从函数主体调用钩子的持续要求会引发错误,因为我是从方法。

权限从哪里来?'ra-core' 怎么称呼这个getPermissions()?为什么.then()getPermissions() 中有一个名为 not a function 的错误?

需要有关于 AuthProvider 这方面的更好的文档来帮助甚至有经验的 react-admin 人员。只是说。

获取权限的钩子:

const useFetchPermissions = ({ emailId }) => {
  const dataProvider = useDataProvider();
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState();
  console.log("fetching permissions");

  const [permissions, setPermissions] = useState();

  useEffect(() => {
    dataProvider
      .getOne("users/permissions", { id: emailId })
      .then(({ data }) => {
        setPermissions(data);
        setLoading(false);
      })
      .catch((error) => {
        setError(error);
        setLoading(false);
      });
  }, []);

  if (loading) return <Loading />;
  if (error) return <Error />;
  if (!permissions) return null;

  return permissions;
};

AuthPRvider 登录方式:

login: () => {
    /* ... */
    console.log("Logging in..");
    //localStorage.setItem("permissions", "CREATE_ITEM");
    return tfsAuthProvider.login();

AuthProvider getPermissions 方法:

getPermissions: () => {
    const role = localStorage.getItem("permissions");
    console.log(role);
    //useFetchPermissions(authProvider.getAccount().userName); throw error
    return role === null ? Promise.resolve() : role;
  },

App.js dataProvider(url,useHttpClient) 调用这个:

const useHttpClient = (url, options = {}) => {
  if (!options.headers) {
    options.headers = new Headers({ Accept: "application/json" });
  }
  // add your own headers here
  //options.headers.set("Access-Control-Allow-Origin", "true");
  //const token = localStorage.getItem("token");
  //const userName = authProvider.getAccount().userName;
  //const [permissions, setPermissions] = useState();
  //const permissions = useFetchPermissions(userName);  throws error

  //localStorage.setItem("permissions", permissions);
  options.headers.set(
    "Authorization",
    `Bearer ${authProvider.getAccount().userName}`
  );
  return fetchUtils.fetchJson(url, options);
};
4

2 回答 2

0

为什么每次都调用 API 来获取用户的权限,如果它们只基于emailId在用户会话中没有改变的那个?

我会在你有两个选择的login方法中进行调用:authProvider

  1. 取决于 API 和后端,您可以(如果您有选项)在复杂的 json 对象或 jwt 中返回权限以及其他用户信息login

  2. 根据成功的emailId登录响应和之后的响应,进行连续调用(如 上面的调用useFetchPermissions)并再次将它们存储在您以后可以访问它们的地方getPermissions()

我没有测试过这段代码,所以它可能会有一些错误,但只是一个想法,你可以如何在没有钩子的情况下构建登录管道。

   login: () => {
      console.log("Logging in..");
      
      tfsAuthProvider
         .login() 
         .then(response => {
             if (response.status < 200 || response.status >= 300) {              
                throw new Error(response.statusText);
             }

             return response.json();
         })
        .then(({ emailId }) => (
             dataProvider.getOne("users/permissions", { id: emailId })
        ))
        .then(({ data }) => {
             const permissionsString = JSON.stringify(permissions);
             // store wherever you want
             localStorage.setItem(userPermissionsKey, permissionsString);                                  
        })
       .catch((error) => {
            throw new Error(error);                
       });
   }
于 2020-09-23T09:00:56.080 回答
0

感谢@KiaKaha 的回答,我能够实现一些对我有用的东西,这是反应钩子例外的解决方法。

编辑:这是一个改进的解决方案

login: () => {
    /* ... */
    console.log("Logging in..");

    console.log(tfsAuthProvider.authenticationState);

   
    return tfsAuthProvider.login().then(async () => {
      const result = await fetch(
        process.env.REACT_APP_BASE_URL +
          "/users/permissions/" +
          tfsAuthProvider.getAccount().userName
      );
      
      const body = await result.json();
      console.log(body);
      localStorage.setItem("permissions", body);
      return Promise.resolve();
    });
   
  },
  1. dataProvider.getOne()方法是一个反应钩子,因此我无法调用它。所以用了fetch()。使用环境变量来获取 dataProvider 使用的 URL。(这仍然是正确的)。

<-- 这之后的一切都是不必要的,可能有助于解决其他问题。-->

  1. response无法直接转换为字符串,所以我使用UTF8response.body.getReader()解码器来解码read().

    login: () => {
    
     console.log("Logging in..");
    
     console.log(tfsAuthProvider.authenticationState);
    
     const utf8Decoder = new TextDecoder("utf-8");
    
     return tfsAuthProvider
       .login()
       .then(() =>
         fetch(
           new Request(
             process.env.REACT_APP_BASE_URL +
               "/users/permissions/" +
               tfsAuthProvider.getAccount().userName,
             {
               method: "GET",
               headers: new Headers({ "Content-Type": "application/json" }),
             }
           )
         )
       )
       .then((response) => {
         if (response.status < 200 || response.status >= 300) {
           throw new Error(response.statusText);
         }
         return response.body.getReader();
       })
       .then((reader) => reader.read())
       .then(({ done, value }) => {
         // if (done) {
         //   controller.close();
         //   return;
         // }
    
         const permissions = utf8Decoder.decode(value);
    
         console.log(permissions);
         localStorage.setItem("permissions", permissions);
         return Promise.resolve();
       });
    },
    

希望这可以帮助任何通过这个兔子洞的人。

更多关于可读流对象 - https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams

更多关于登录实现 - https://marmelab.com/react-admin/Authorization.html

于 2020-09-28T09:28:39.500 回答