JS:如何通过重定向函数将url传递到登录函数



在我的React/nextJS应用程序中,我正在检查getInitialProps静态函数中的有效令牌。我用这个作为HOC——但在这种情况下这应该无关紧要。

如果令牌无效(或丢失(,则用户将被重定向到登录页面。这是由redirect函数完成的,如下所示。到目前为止,一切都很好。

如何将用户重定向到登录组件的页面的url传递给用户?

如果用户未登录并且正在调用类似的内容http://my-server.com/any-page,他被重定向到索引页面(http://my-server.com(:会有一个登录表单。如果登录成功,我想将他重定向回第一个被调用的页面:http://my-server.com/any-page

  1. 以未登录用户身份调用受限页面
  2. 重定向到索引登录页
  3. 登录后重定向回第1页

我不知道如何将这些信息传递给登录功能。。。

使用服务器道具.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} />
}
}

重定向.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
})
}
})
}

with-server-props.js中,用URL对象替换路径

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)

希望有帮助,让我知道。

您需要的是react-router或更具体地说是react-router-dom包。如果你了解它的工作方式,那就轻而易举了。

对于您的场景,您使用<Redirect to={url} />,而不是在未进行身份验证时调用redirect()。这会自动执行浏览器url替换和更新全局状态。不过,你已经巧妙地分配了一个与任何特殊情况相匹配的url。例如,"/login/ref/:toref"将是处理url"/login/ref/{specialaccess}"的基表达式。

注意":"。它是params匹配器,用于检索登录组件中的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.locationthis.props.historythis.props.match,因为我们已经将应用程序的根组件放置在包中默认可用的<BrowserRouter><BrowserRouter/>HOC中。

使用this.props.match,我们可以很容易地引用并重定向回我们之前在":toref"中指定的url。

你可以在这里阅读更多关于react-router

jwt.verify函数以异步回调方式使用。

这种风格更适合以这种方式使用的WrappedComponentcomponentDidMount生命周期方法
为其传递回调意味着isValid的值可能永远不会更新得足够早,即使客户端JWT令牌是有效的,并且用户将始终被重定向。

我建议使用不带回调的同步变体(测试以比较在呈现封装组件之前的时间(。更好的是,将jwt.verify回调样式转换为返回promise的函数,以便在getInitialPropsasync函数的情况下,可以在await表达式中解析它。

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

将返回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.push,而不是Router.replace。希望这能有所帮助。

最新更新