web-dev-qa-db-ja.com

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のページにリダイレクトします。

この情報をログイン機能に渡す方法がわかりません...

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
      })
    }
  })
}
10
user3142695

あなたのwith-server-props.jsパスを RLオブジェクト に置き換えます

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)

それがお役に立てば幸いです、私に知らせてください。

2
Laszlo

必要なのは_react-router_、より具体的には_react-router-dom_パッケージです。それがどのように機能するかを理解していれば、それは簡単です。

シナリオでは、認証されていないときにredirect()を呼び出す代わりに、_<Redirect to={url} />_を使用します。これにより、ブラウザの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.location_、_this.props.history_、および_this.props.match_が提供されます。これは、アプリのルートコンポーネントがパッケージからデフォルトで利用可能な_<BrowserRouter><BrowserRouter/>_ HOC内に既に配置されているためです。

_this.props.match_を使用すると、以前に「:toref」で指定したURLを簡単に参照してリダイレクトできます。

_react-router_ ここ についてもっと読むことができます

0
Caleb Lucas

jwt.verify関数は非同期コールバック方式で使用されます。

そのスタイルは、そのように使用されるcomponentDidMountWrappedComponentライフサイクルメソッドにより適しています。
コールバックを渡すと、クライアントJWTトークンが有効なトークンであり、ユーザーが常にリダイレクトされる場合でも、isValidの値が十分に早く更新されない可能性があります。

コールバックなしで同期バリアントを使用することをお勧めします(ラップされたコンポーネントがレンダリングされるまでの時間を比較するためのテスト)。さらに良いことに、jwt.verifyコールバックスタイルをpromiseを返す関数に変換して、awaitgetInitialProps関数である場合に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}`);
0
Oluwafemi Sule

戻り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の代わりに、HOCから渡された戻りURLを使用してRouter.Pushを試してください。お役に立てれば。

0