如何在 react-admin 的 AuthProvider 中配置 getPermissions() 方法?

How do I configure the getPermissions() method in the AuthProvider in react-admin?

我已经尝试创建自定义挂钩来调用 DataProvider getOne() 方法,以根据登录后从 authProvider 获得的用户名获取权限,但始终需要从函数抛出错误,因为我从方法中调用它。

权限从何而来? 'ra-core' 怎么称呼这个 getPermissions()?为什么有一个名为 .then() 的错误不是 getPermissions() 中的函数?

在 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;
};

AuthPProvider 登录方式:

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);
};

为什么每次都调用 API 来获取用户权限,如果它们仅基于 emailId 而在整个用户会话期间都不会更改?

我会在 authProviderlogin 方法中调用,您有两个选择:

  1. 取决于 API 和后端,您可以(如果您有选择)return 复杂 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);                
       });
   }

感谢@KiaKaha 的回答,我能够实现一些对我有用的东西,这是 react-hooks.

异常的解决方法

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

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() 方法是 react-hook,因此我无法调用它。所以用了fetch()。使用环境变量获取 dataProvider 使用的 URL。 (这仍然是正确的)。

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

  1. response不能直接转成字符串所以我用response.body.getReader()和UTF8解码器解码read().[=19=的结果]

    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