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.
Я понятия не имею, как передать эту информацию в функцию входа в систему...
с-сервера-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)
}
}
страниц/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
})
}
})
}
Ответы
Ответ 1
В вашем 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
тогда вы можете получить параметры URL на любой странице, используя getInitialProps
:
this.redirectUrl = (req && req.query['redirect']) ? decodeURIComponent(req.query['redirect']) : '/'
в конце концов
window.location.assign(this.redirectUrl)
надеюсь, это поможет, дайте мне знать.
Ответ 2
Что вам нужно, это react-router
или, более конкретно, пакет react-router-dom
. Это бриз, если вы понимаете, как это работает.
Для вашего сценария вместо вызова redirect()
когда он не аутентифицирован, вы используете <Redirect to={url}/>
. Это автоматически заменяет 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/>
доступный по умолчанию из пакета.
С помощью this.props.match
мы можем легко ссылаться и перенаправлять на URL, который мы указали в ": toref" ранее.
Вы можете прочитать больше о react-router
здесь
Ответ 3
Функция jwt.verify
используется в асинхронном режиме обратного вызова.
Этот стиль более подходит для componentDidMount
метод Жизненный цикл WrappedComponent
используется таким образом.
Передача обратного вызова для него означает, что значение для isValid
никогда не может быть обновлено достаточно рано, даже если клиентский токен JWT является допустимым и пользователь всегда будет перенаправлен.
Я предлагаю использовать синхронный вариант без обратного вызова (проверьте, сколько времени прошло до того, как будет обработан упакованный компонент). Более того, преобразуйте jwt.verify
обратного вызова 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
для перенаправления пользователя вы можете получить значение параметра запроса ref
установленное в WrappedComponent.getInitialProps
и использовать его для перенаправления пользователя.
const ref = new URLSearchParams(location.search).get('ref');
location.assign('/${ref}');
Ответ 4
Передайте возвращаемый 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>
)
Вместо Router.replace, попробуйте Router.push с обратным URL-адресом, переданным из HOC. Надеюсь это поможет.