読者です 読者をやめる 読者になる 読者になる

鈍足ランナーのIT日記

走るのが好きな5流のITエンジニアのブログ。

趣味の範囲は広いけど、どれも中途半端なクソブロガー楽しめるWebアプリを作ってあっと言わせたい。サーバーサイドPerl(Mojolicious)、クライアントサイドVue.js。Arduinoにも触手を伸ばす予定。

Auth0 + React-Routerで認証を楽にこなそうとしているが楽ではない。

SPAで認証をしようとすると。Webベースのリダイレクトガンガンの
ような認証ができないしなぁと思っていたら。
そういう要望に応えたのがOAuth2というものということらしい。
Auth0という認証サービスが便利らしいので試してみる。

React+ auth0

React+auth0のサンプルは以下にあり。auth0のcallbackの
設定を「http://localhost:3000/index.html」とすると動作しました。

github.com

React-Router + auth0

さて、次にReact-Routerと組み合わせて使ってみます。
npmパッケージをインストール!

npm install auth0-lock --save
cd node_modules
cd auth0-lock
npm install ejsify
npm install packageify
npm install brfs

react-routerを使っているので・・
こんなかんじですべてのコンポーネントにlockプロパティを設定する。

import Auth0Variables from 'auth0-variables'
import Auth0Lock from 'auth0-lock'

const history = createHistory()

function createElement(Component, props) {
    props.lock = new Auth0Lock(Auth0Variables.AUTH0_CLIENT_ID, Auth0Variables.AUTH0_DOMAIN);
    return <Component  {...props} />
}

React.render((
  <Router history={history} createElement={createElement}>
    <Route path="/" component={App}>
      <Route path="/home" component={Home} />
      <Route path="/login" component={Login} />
      <Route path="/logout" component={Logout} />
    </Route>
  </Router>
), document.getElementById('example'))

Loginコンポーネントの中で認証させたいのでこんなかんじにしてみる。
さて認証画面が表示されるでしょうか?!

class Login extends React.Component {

  showLock: function() {
    this.props.lock.show();
  }
  render: function() {
    return (
    <div>
      <button onClick={this.showLock}>Login</button>
    </div>);
  }
}


これだけで、認証画面が表示されます。
でも、認証成功後にエラーとなってしまった。

Auth0のログ(左メニューのLogsを押す)を読んでみると

Description: Callback URL mismatch. http://localhost:8080/login is not in the list of authorized callback URLs: http://localhost:8080/callback 

どうもAuth0の管理画面に設定したコールバックの設定「http://localhost:8080/callback」がだめ
と言っているようです。

SPAなのでコールバックってなんだろうという感じもしますが。
Auth0が呼んでくれるのかな?
でもAuth0側からlocalhostを呼ぶっていうのも、なんか変な気もするとか考えたり。
紋々としていましたが・・


開発環境ではhttp://localhost:8080/loginで認証画面が表示するように
しています。では、「http://localhost:8080/login
をAuth0の設定画面のcallback urlに設定してみようではないか。

うまくできたけれども・・・

認証が済むと、コールバックでこんなかんじで帰ってくるようになった。http://localhost:8080/login#access_token=foo,user_token=bar
そうするとReact.jsでパスを処理したいのですが・・
処理されずブラウザはHTTPアクセスにいってしまうのです。
login#ホニャララをLoginコンポーネントで処理したいのに。

React.render((
  <Router history={history} createElement={createElement}>
    <Route path="/" component={App}>
      <Route path="/home" component={Home} >
        <Route path="/stamp/:stamp" components={{ content: Stamp, sidebar: StampSidebar }}>
          <Route path=":image" component={StampCanvas} />
        </Route>
      </Route>
      <Route path="/login" component={Login} />
      <Route path="/logout" component={Logout} />
      <Route path="/new" component={New} />
    </Route>
  </Router>
), document.getElementById('example'))

こんな風に変えてみたけど、ダメだぁ。
Not working!!

React.render((
  <Router history={history} createElement={createElement}>
    <Route path="/" component={App}>
      <Route path="/home" component={Home} >
        <Route path="/stamp/:stamp" components={{ content: Stamp, sidebar: StampSidebar }}>
          <Route path=":image" component={StampCanvas} />
        </Route>
      </Route>
      <Route path="/login(#**)" component={Login} />
      <Route path="/logout" component={Logout} />
      <Route path="/new" component={New} />
    </Route>
  </Router>
), document.getElementById('example'))


あららら。わからない。

React-Router経由にするとcallback(Redirect)でブラウザがHTTPアクセス
してしまう。どうして、単体Reactでは動作するのだろう?

ここまできてやっと気づいた

認証後にリダイレクトが起きて動くようにしておかなくてはいけないということ。/loginには実際にはコンテンツがないわけで
historyAPIでpushstateして履歴を積み上げているだけで
/loginへのページの実体は存在していないから。

ルートから認証させる必要あり

/loginで認証させるのではなくて/から認証させる必要あり。
メニューで認証させるのをやめよう。