1

我有这种情况。

  • 用户在/company/<company-id>地址栏中输入。
  • 由于应用程序与后端完全分离,因此它需要预取公司。
  • 正常的用户流是/login-> /company/。我很好地处理了这个案例,/company/<whatever id is first in the prefetch>并且没有问题地导航到。
  • 但是如果你用 id加载呢?我有解决方案,但我觉得我在路由中误解了一些东西。

companyState.success您可能会假设我的预取有效,并且下面的代码片段只有在为真时才会触发。就像我说的,它正在工作。我手动处理了这个,通过

// pretty sure i can handle this with regex better to capture other cases
// but that's beside the point for the scope of this question
const urlId = +location.pathname.replace("/company/", "")
const checkCompany = !!companyState.data.find(d => d.id === urlId)
if(checkCompany){
  company.set(urlId)
}
else{
  navigate("/404")
}

我有钩子,如果company.set(<company:id>)确实更新,它将预先获取视图所需的所有其他内容。而且,company是一个自定义上下文挂钩,因此它在我的应用程序中无处不在。

有没有更好的方法来处理这个问题?手动检查路径名似乎是 hack-y。您可以假设 mygatsby_node.js具有正确的定义以允许客户端路由。

这是我的路由定义:(这是我放在 pages 文件夹中的内容)

const DashboardPage = () => (
  <ProtectedRoute>
    <Router>
      <Company path="/company/*" />
    </Router>
  </ProtectedRoute>
)

最后在组件文件夹中,

const Company = ({location}) => (
    <Router>
      <Main path="/:companyId">
        <Summary path="/" />
        .... other dashboard routes
      </Main>
    </Router>
)
4

2 回答 2

0

因此,我没有手动处理路由,而是仅使用 ReachRouter 的导航来模拟history.push()以避免重新渲染整个页面。(类似地,只是为了跟踪历史而进行的状态更改)。后端受到身份验证令牌的完全保护,因此无需担心。

我下面的策略将处理这些情况:

  • 用户输入或应用导航到/company(应用将预取 > 默认情况下获取第一家公司 > 导航到/company/{id}
  • 用户输入或应用导航到/company/{id}(应用将预取 > 导航到/company/{id}> 由该路由触发的组件将检查 id 的有效性,否则导航到 404)

我创建的策略是,

  • 创建一个默认加载加载屏幕的组件并预取上述公司。
  • pages在我的情况下,默认调用文件夹中的上述组件,/company应该是pages > company.jspages > company > index.js
  • 如果预取成功,则导航到/company/{id}该组件的子组件,这是一个纯粹的客户端路由。
  • 确保gatsby-node.js有必要的createPages定义以允许客户端路由所有内容/company/*
  • 手动检查当前位置是否/company拒绝重定向以捕获用户输入时的第二种情况/company/{id}

如果我显示代码会更好,忽略我自定义的内置钩子。

useRequest只是给出了一个 axios 类,true参数告诉它是一个经过身份验证的必需请求。 useApi只是提供了一个方便的(async-await)函数,包括dispatch用于 redux 状态并调用 api 本身。我正在使用thunk,所以success并且error是标准的。

const CompanyDefault = ({location}) => {

  const [loading, toggle] = useState(true)

  const request = useRequest(true)
  const companyApi = useApi(request, getCompanies)
  const companyState = useSelector(({company}) => company)
  const redirectToCompany = async () => await navigate(clientRoutes.COMPANY(companyState.data[0].id))

  const fetchCompanies = async () => {
    await companyApi()
    toggle(false)
  }

  useEffect(() => {
    if(companyState.data.length === 0){
      fetchCompanies()
    } 
  }, [])

  if(loading){
    return <Loading />
  }
  else if(companyState.error || companyState.data.length === 0){
    return <Error callApi={companyApi} />
  }
  else if(companyState.success && (location.pathname === "/company" || location.pathname === "/company/")){
    redirectToCompany()
  }

  return (
    <Router>
      <Company path="company/:companyId/*" />
    </Router>
  )
}

export default CompanyDefault

因此,公司模块将只是

const Company = ({companyId}) => (
    // you now have companyId! 
    // do magic here, and check if that company id is valid.
    <Router>
      <Main path="/">
        <Summary path="/" />
        .... other dashboard routes
      </Main>
    </Router>
)

希望这更清洁。如果有更好的方法请告诉我!:D

于 2019-10-18T01:43:15.080 回答
0

您必须假设客户端代码总是可以被恶意行为者更改。最终,您必须确保在后端用户只能请求他应该看到的资源。

您的客户端解决方案对我来说似乎很好。除了手动检查 URL 路径然后重定向之外,我没有看到其他方法。

通过登录,您的用户需要被分配到加密安全的 cookie 或令牌(例如 JSON Web 令牌),以便您始终可以确定他们的身份。每次将公司 ID 路由到时,您的前端都需要将用户身份发送到您的后端。只有在那里你才能免受代码操作的影响。您的后端需要检查用户是否可以查看此页面。

  • 如果用户可以:您的后端发送页面数据
  • 如果用户不能:您的后端发送“未授权”消息并且您的前端重定向

这样,即使有人操纵了您的客户端代码并取消了重定向,黑客也会盯着一个无用的空白页面。

总之:

您在客户端的方法很好。确保您的后端在发送公司数据之前检查用户的身份。

于 2019-10-16T09:30:56.710 回答