JS:如何通过重定向功能将url传递给登录功能
Posted
技术标签:
【中文标题】JS:如何通过重定向功能将url传递给登录功能【英文标题】:JS: How to pass url through redirect function to login function 【发布时间】:2019-04-20 16:41:33 【问题描述】:在我的 React/nextJS 应用程序中,我正在检查 getInitialProps
静态函数中的有效令牌。
我将其用作 HOC - 但在这种情况下这无关紧要。
如果令牌无效(或丢失),用户将被重定向到登录页面。这是由redirect
函数完成的,如下所示。到目前为止,一切顺利。
如何将用户从其重定向到登录组件的页面的 url 传递?
如果用户没有登录并且正在调用类似 http://my-server.com/any-page 的东西,他会被重定向到索引页面 (http://my-server.com):会有一个登录表格。如果登录成功,我想将他重定向回第一个调用页面:http://my-server.com/any-page
-
以未登录用户的身份调用受限页面
重定向到索引登录页面
登录后重定向回1的页面。
我不知道如何将此信息传递给登录功能...
with-server-props.js
export default WrappedComponent =>
class extends Component
static async getInitialProps (context)
const req, pathname = context
let isValid = false
if (req && req.headers)
const cookies = req.headers.cookie
if (typeof cookies === 'string')
const cookiesJSON = jsHttpCookie.parse(cookies)
initProps.token = cookiesJSON['auth-token']
if (cookiesJSON['auth-token'])
jwt.verify(cookiesJSON['auth-token'], secret, (error, decoded) =>
if (error)
console.error(error)
else
isValid = true
)
// Redirect to index (=login) page if isValid is false
if (!isValid && pathname && pathname !== '/')
redirect(context, pathname ? '/?ref=' + pathname : '/')
return initProps
render ()
return <WrappedComponent ...this.props />
redirect.js
import Router from 'next/router'
export default (context, target) =>
if (context.res)
// server
context.res.writeHead(303, Location: target )
context.res.end()
else
// In the browser, we just pretend like this never even happened ;)
Router.replace(target)
pages/index.js
在 index.js 上有 submit
函数来登录用户。在那里,用户应该被重定向到初始页面:
_onSubmit (event)
this.props.loginMutation(
variables: username, password
).then(response =>
const token = response.data.token
if (token)
Cookies.set('auth-token', token, expires: 1 )
this.props.client.resetStore().then(() =>
window.location.assign('/') // <-- Redirect to initial called page
)
)
【问题讨论】:
可能只是将初始url存储到本地/会话存储中,登录后查看? 在 react 中传递数据最优雅的方式是通过 props。但是 'next/router' 正在做路由,所以你无法通过 props 传递数据。而且由于您是替换而不是推送,因此它也不会保存在“历史记录”中。除了 props,还有多种传递数据的方式,例如“全局变量”、“本地存储”、“redux 等第三方存储”。我认为使用“redux”或其他商店是更好的数据共享方式。 【参考方案1】:您需要的是 react-router
或更具体地说是 react-router-dom
包。如果您了解它的工作方式,那就轻而易举了。
对于您的场景,您可以使用<Redirect to=url />
,而不是在未通过身份验证时调用redirect()
。这会自动替换浏览器 url 并更新全局状态。您已经巧妙地分配了一个匹配任何特殊情况的 url 以进行陷阱。例如。 "/login/ref/:toref" 将是处理 url "/login/ref/specialaccess" 的基本表达式。
注意“:”。它是参数匹配器,需要在登录组件中检索 url。
正如他们所说,一行代码值一千字。所以我做了一个小项目来充分展示如何实现react-router-dom
的一些重要特性。
在这里找到:https://codesandbox.io/s/y0znxpk30z
在项目中,当您尝试通过浏览器模拟器访问https://y0znxpk30z.codesandbox.io/specialaccess 时,在登录时通过身份验证后,您会被重定向到特殊访问页面。否则,如果您访问https://y0znxpk30z.codesandbox.io,那么您会在登录后被重定向到主页。
请记住,您必须像这样包装任何需要全局道具 withRouter
的组件:
export default withRouter(component-name);
这会在每个组件中提供this.props.location
、this.props.history
和this.props.match
,因为我们已经将应用程序的根组件放置在包中默认可用的<BrowserRouter><BrowserRouter/>
HOC 中。
使用this.props.match
,我们可以轻松引用并重定向回我们之前在 ":toref" 中指定的 url。
你可以阅读更多关于react-router
here
【讨论】:
听起来不错。我不太确定,但是 nextJS 也有一个路由模块。如果是这种情况,是否可以以类似的方式使用它? 可能类似于github.com/zeit/next.js/#using-a-higher-order-component ? 是的,nextJS 有它的路由模块,但它不像react-router
那样处理复杂的路由。正如你可以从这里读到的,react-etc.net/entry/next-js-to-adopt-react-routerreact-router
仍将被 nextJS 采用。所以,如果你在前端做动态路由,react-router
仍然是你最好的选择,至少据我所知。【参考方案2】:
jwt.verify
函数以异步回调方式使用。
这种风格更适合 WrappedComponent
的 componentDidMount
生命周期方法。
为其传递回调意味着 isValid
的值可能永远不会更新得足够早,即使客户端 JWT 令牌是有效的令牌并且用户将始终被重定向。
我建议使用不带回调的同步变体(测试以比较包装组件被渲染之前的时间)。更好的是,将jwt.verify
回调样式转换为返回承诺的函数,以便它可以在await
表达式中解析,因为getInitialProps
是async
函数。
if (req && req.headers)
const cookies = req.headers.cookie
if (typeof cookies === 'string')
const cookiesJSON = jsHttpCookie.parse(cookies)
initProps.token = cookiesJSON['auth-token']
if (cookiesJSON['auth-token'])
try
const payload = jwt.verify(cookiesJSON['auth-token'], secret)
if (payload)
isValid = true
catch (err)
isValid = false
现在在_onsubmit
方法重定向用户,你可以得到WrappedComponent.getInitialProps
中设置的ref
查询参数值,并用它来重定向用户。
const ref = new URLSearchParams(location.search).get('ref');
location.assign(`/$ref`);
【讨论】:
【参考方案3】:将返回 url 作为查询参数或位置状态传递给登录页面。我在 Next.js 的文档页面上找到了一个使用查询参数推送路由的示例。
import Router from 'next/router'
const handler = () =>
Router.push(
pathname: '/about',
query: name: 'Zeit'
)
export default () => (
<div>
Click <span onClick=handler>here</span> to read more
</div>
)
尝试使用从 HOC 传入的返回 url,而不是 Router.replace。希望这会有所帮助。
【讨论】:
【参考方案4】:在您的 with-server-props.js
中,将路径替换为 URL object
redirect(context,
pathname: '/',
query: redirect: req.url // req.url should give you the current url on server side
)
这会将重定向参数添加到 url https://example.com/?redirect=/about
然后您可以使用getInitialProps
获取任何页面上的 url 参数:
this.redirectUrl = (req && req.query['redirect']) ? decodeURIComponent(req.query['redirect']) : '/'
终于
window.location.assign(this.redirectUrl)
希望有帮助,告诉我。
【讨论】:
以上是关于JS:如何通过重定向功能将url传递给登录功能的主要内容,如果未能解决你的问题,请参考以下文章
重定向页面时如何将jwt存储在cookie中并将其传递给身份验证功能?