Next.js: ログイン/認証の例を追加

作成日 2016年10月29日  ·  208コメント  ·  ソース: vercel/next.js

と:

  • ページ間で再利用可能な認証ヘルパー
  • タブ間のセッション同期
  • now.shホストされているシンプルなパスワードなしのメールバックエンド

これは多くの新規参入者にとって非常に役立つと思います。

最も参考になるコメント

だから私は認証が泳いで働いています。 他の場所で述べたように、それはクライアント側のみであり、最終的には戦いの半分にすぎません。

「かなり安全」

phpと同様に、Nextのアトミックユニットはページです。 最も優れた機能の1つは、要求された場合にのみ各ページを遅延ロードすることです。 クライアント側のみの認証で、サーバーレンダリングでは、その保護されたページのjsは実際にはブラウザによってダウンロードされます。 将来、Nextがサーバーワークフローを追加するときに、サーバーでのレンダリングとリダイレクトをブロックして、これを完全に防ぐことができるようになることを願っています。 これにはCookie、セッション、およびAFAIKセッションストアが必要ですが、これはこれらのようなハイブリッドアプリを実行するためのコストにすぎません。

認証例

/token/me 2つのエンドポイントを持つJWTで保護されたAPIがあるとします。 /tokenは、電子メール/パスワードの資格情報を受け入れ、署名されたJWT( id_token )を返します。一方、 /meは、JWTで認証されたユーザーに関連するプロファイル情報を返します。 Auth0のロックから次のAuthService.jsを採用しました(イベントエミッターを削除しますが、これは最悪の考えではありません)。 ほとんどすべてのJWTトークン処理を抽出するため、ログインページや高階コンポーネント(詳細は後で説明します)でも使用できます。

// utils/AuthService.js
export default class AuthService {
  constructor(domain) {
    this.domain = domain || 'http://localhost:5000'
    this.fetch = this.fetch.bind(this)
    this.login = this.login.bind(this)
    this.getProfile = this.getProfile.bind(this)
  }

  login(email, password) {
    // Get a token
    return this.fetch(`${this.domain}/token`, {
      method: 'POST',
      body: JSON.stringify({
        email,
        password
      })
    }).then(res => {
      this.setToken(res.id_token)
      return this.fetch(`${this.domain}/user`, {
        method: 'GET'
      })
    }).then(res => {
      this.setProfile(res)
      return Promise.resolve(res)
    })
  }

  loggedIn(){
    // Checks if there is a saved token and it's still valid
    const token = this.getToken()
    return !!token && !isTokenExpired(token) // handwaiving here
  }

  setProfile(profile){
    // Saves profile data to localStorage
    localStorage.setItem('profile', JSON.stringify(profile))
  }

  getProfile(){
    // Retrieves the profile data from localStorage
    const profile = localStorage.getItem('profile')
    return profile ? JSON.parse(localStorage.profile) : {}
  }

  setToken(idToken){
    // Saves user token to localStorage
    localStorage.setItem('id_token', idToken)
  }

  getToken(){
    // Retrieves the user token from localStorage
    return localStorage.getItem('id_token')
  }

  logout(){
    // Clear user token and profile data from localStorage
    localStorage.removeItem('id_token');
    localStorage.removeItem('profile');
  }

  _checkStatus(response) {
    // raises an error in case response status is not a success
    if (response.status >= 200 && response.status < 300) {
      return response
    } else {
      var error = new Error(response.statusText)
      error.response = response
      throw error
    }
  }

  fetch(url, options){
    // performs api calls sending the required authentication headers
    const headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }

    if (this.loggedIn()){
      headers['Authorization'] = 'Bearer ' + this.getToken()
    }

    return fetch(url, {
      headers,
      ...options
    })
    .then(this._checkStatus)
    .then(response => response.json())
  }
}

次は、ページの保護を簡単にするためのHOCです。 機密情報の不要なフラッシュを防ぐために、reactが起動/ localStorageからトークンを読み取る間、ページは最初のレンダリングでLoading...をサーバーレンダリングします。 これは、保護されたページがSEOを行わないことを意味します。これはおそらく現時点では問題ありませんが、間違いなく最適ではありません。

// utils/withAuth.js - a HOC for protected pages
import React, {Component} from 'react'
import AuthService from './auth'

export default function withAuth(AuthComponent) {
    const Auth = new AuthService('http://localhost:5000')
    return class Authenticated extends Component {
      constructor(props) {
        super(props)
        this.state = {
          isLoading: true
        };
      }

      componentDidMount () {
        if (!Auth.loggedIn()) {
          this.props.url.replaceTo('/')
        }
        this.setState({ isLoading: false })
      }

      render() {
        return (
          <div>
          {this.state.isLoading ? (
              <div>LOADING....</div>
            ) : (
              <AuthComponent {...this.props}  auth={Auth} />
            )}
          </div>
        )
      }
    }
}
// ./pages/dashboard.js
// example of a protected page
import React from 'react'
import withAuth from  '../utils/withAuth'

class Dashboard extends Component {
   render() {
     const user = this.props.auth.getProfile()
     return (   
         <div>Current user: {user.email}</div>
     )
   }
}

export default withAuth(Dashboard) 

ログインはパブリックである必要があるため、ログインページは現在のHOCを使用できません。 したがって、AuthServiceのインスタンスを直接作成するだけです。 サインアップページでも同様のことを行います。

// ./pages/login.js
import React, {Component} from 'react'
import AuthService from '../utils/AuthService'

const auth = new AuthService('http://localhost:5000')

class Login extends Component {
  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  componentDidMount () {
    if (auth.loggedIn()) {
      this.props.url.replaceTo('/admin')   // redirect if you're already logged in
    }
  }

  handleSubmit (e) {
    e.preventDefault()
    // yay uncontrolled forms!
    auth.login(this.refs.email.value, this.refs.password.value)
      .then(res => {
        console.log(res)
        this.props.url.replaceTo('/admin')
      })
      .catch(e => console.log(e))  // you would show/hide error messages with component state here 
  }

  render () {
    return (
      <div>
         Login
          <form onSubmit={this.handleSubmit} >
            <input type="text" ref="email"/>
            <input type="password" ref="password"/>
            <input type="submit" value="Submit"/>
          </form>
      </div>
    )
  }
}

export default Login

Airbnbのreact-with-stylesに触発されて、 next-with-auth libの作業も開始しました。これは、ページで使用するHOCを返す関数です。 また、 AuthServiceとこのHOCをマージして遊んだ。 1つの解決策は、このHOCに、redux connectのように、コンポーネントに加えてアクセス許可レベルの関数を引数として受け入れるようにすることです。 とにかく、私の考えでは、次のようにnext-with-authを使用します。

// ./utils/withAuth.js
import nextAuth from 'next/auth'
import parseScopes from './parseScopes'

const Loading = () => <div>Loading...</div>

export default nextAuth({
  url: 'http://localhost:5000',
  tokenEndpoint: '/api/token',
  profileEndpoint: '/api/me',
  getTokenFromResponse: (res) => res.id_token,
  getProfileFromResponse: (res) => res,
  parseScopes,
})

Reduxでこれをすべて行うことは不必要に複雑に見えましたが、基本的にはwikiの例に従うことができますが、AuthServiceをアクション(ログインとログアウト)に移動し、UserReducerを使用します。 ただし、サーバーにはlocalStorageがないため、クライアントでのみこれらのアクションを呼び出すことができます。そのため、アクションでそれを確認する必要があります。 最終的に、reduxストアはとにかくwindow置かれます。 したがって、コンテキストを使用する代わりに、ユーザーを自分でwindowにキャッシュすることができます。 reduxが必要ない場合は、 react-broadcast試すこともできます。

最後に、 next/serverが#25に従って出荷されると仮定します。 next-with-authは、ミドルウェアとHOCを使用して、複雑なlocalStorageとCookieを開発者から遠ざけることができます。 トークンの更新も処理できます。

全てのコメント208件

提案:ReduxとJWTを使用して例を実行します

私はこの例に取り組んでいます。 現在、高レベルのコンポーネントでcomponentWillReceivePropsを起動する際に問題が発生しています(ユーザーが認証されているかどうかを確認し、認証されていない場合はログインページにリダイレクトする予定です)

だから私は認証が泳いで働いています。 他の場所で述べたように、それはクライアント側のみであり、最終的には戦いの半分にすぎません。

「かなり安全」

phpと同様に、Nextのアトミックユニットはページです。 最も優れた機能の1つは、要求された場合にのみ各ページを遅延ロードすることです。 クライアント側のみの認証で、サーバーレンダリングでは、その保護されたページのjsは実際にはブラウザによってダウンロードされます。 将来、Nextがサーバーワークフローを追加するときに、サーバーでのレンダリングとリダイレクトをブロックして、これを完全に防ぐことができるようになることを願っています。 これにはCookie、セッション、およびAFAIKセッションストアが必要ですが、これはこれらのようなハイブリッドアプリを実行するためのコストにすぎません。

認証例

/token/me 2つのエンドポイントを持つJWTで保護されたAPIがあるとします。 /tokenは、電子メール/パスワードの資格情報を受け入れ、署名されたJWT( id_token )を返します。一方、 /meは、JWTで認証されたユーザーに関連するプロファイル情報を返します。 Auth0のロックから次のAuthService.jsを採用しました(イベントエミッターを削除しますが、これは最悪の考えではありません)。 ほとんどすべてのJWTトークン処理を抽出するため、ログインページや高階コンポーネント(詳細は後で説明します)でも使用できます。

// utils/AuthService.js
export default class AuthService {
  constructor(domain) {
    this.domain = domain || 'http://localhost:5000'
    this.fetch = this.fetch.bind(this)
    this.login = this.login.bind(this)
    this.getProfile = this.getProfile.bind(this)
  }

  login(email, password) {
    // Get a token
    return this.fetch(`${this.domain}/token`, {
      method: 'POST',
      body: JSON.stringify({
        email,
        password
      })
    }).then(res => {
      this.setToken(res.id_token)
      return this.fetch(`${this.domain}/user`, {
        method: 'GET'
      })
    }).then(res => {
      this.setProfile(res)
      return Promise.resolve(res)
    })
  }

  loggedIn(){
    // Checks if there is a saved token and it's still valid
    const token = this.getToken()
    return !!token && !isTokenExpired(token) // handwaiving here
  }

  setProfile(profile){
    // Saves profile data to localStorage
    localStorage.setItem('profile', JSON.stringify(profile))
  }

  getProfile(){
    // Retrieves the profile data from localStorage
    const profile = localStorage.getItem('profile')
    return profile ? JSON.parse(localStorage.profile) : {}
  }

  setToken(idToken){
    // Saves user token to localStorage
    localStorage.setItem('id_token', idToken)
  }

  getToken(){
    // Retrieves the user token from localStorage
    return localStorage.getItem('id_token')
  }

  logout(){
    // Clear user token and profile data from localStorage
    localStorage.removeItem('id_token');
    localStorage.removeItem('profile');
  }

  _checkStatus(response) {
    // raises an error in case response status is not a success
    if (response.status >= 200 && response.status < 300) {
      return response
    } else {
      var error = new Error(response.statusText)
      error.response = response
      throw error
    }
  }

  fetch(url, options){
    // performs api calls sending the required authentication headers
    const headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }

    if (this.loggedIn()){
      headers['Authorization'] = 'Bearer ' + this.getToken()
    }

    return fetch(url, {
      headers,
      ...options
    })
    .then(this._checkStatus)
    .then(response => response.json())
  }
}

次は、ページの保護を簡単にするためのHOCです。 機密情報の不要なフラッシュを防ぐために、reactが起動/ localStorageからトークンを読み取る間、ページは最初のレンダリングでLoading...をサーバーレンダリングします。 これは、保護されたページがSEOを行わないことを意味します。これはおそらく現時点では問題ありませんが、間違いなく最適ではありません。

// utils/withAuth.js - a HOC for protected pages
import React, {Component} from 'react'
import AuthService from './auth'

export default function withAuth(AuthComponent) {
    const Auth = new AuthService('http://localhost:5000')
    return class Authenticated extends Component {
      constructor(props) {
        super(props)
        this.state = {
          isLoading: true
        };
      }

      componentDidMount () {
        if (!Auth.loggedIn()) {
          this.props.url.replaceTo('/')
        }
        this.setState({ isLoading: false })
      }

      render() {
        return (
          <div>
          {this.state.isLoading ? (
              <div>LOADING....</div>
            ) : (
              <AuthComponent {...this.props}  auth={Auth} />
            )}
          </div>
        )
      }
    }
}
// ./pages/dashboard.js
// example of a protected page
import React from 'react'
import withAuth from  '../utils/withAuth'

class Dashboard extends Component {
   render() {
     const user = this.props.auth.getProfile()
     return (   
         <div>Current user: {user.email}</div>
     )
   }
}

export default withAuth(Dashboard) 

ログインはパブリックである必要があるため、ログインページは現在のHOCを使用できません。 したがって、AuthServiceのインスタンスを直接作成するだけです。 サインアップページでも同様のことを行います。

// ./pages/login.js
import React, {Component} from 'react'
import AuthService from '../utils/AuthService'

const auth = new AuthService('http://localhost:5000')

class Login extends Component {
  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  componentDidMount () {
    if (auth.loggedIn()) {
      this.props.url.replaceTo('/admin')   // redirect if you're already logged in
    }
  }

  handleSubmit (e) {
    e.preventDefault()
    // yay uncontrolled forms!
    auth.login(this.refs.email.value, this.refs.password.value)
      .then(res => {
        console.log(res)
        this.props.url.replaceTo('/admin')
      })
      .catch(e => console.log(e))  // you would show/hide error messages with component state here 
  }

  render () {
    return (
      <div>
         Login
          <form onSubmit={this.handleSubmit} >
            <input type="text" ref="email"/>
            <input type="password" ref="password"/>
            <input type="submit" value="Submit"/>
          </form>
      </div>
    )
  }
}

export default Login

Airbnbのreact-with-stylesに触発されて、 next-with-auth libの作業も開始しました。これは、ページで使用するHOCを返す関数です。 また、 AuthServiceとこのHOCをマージして遊んだ。 1つの解決策は、このHOCに、redux connectのように、コンポーネントに加えてアクセス許可レベルの関数を引数として受け入れるようにすることです。 とにかく、私の考えでは、次のようにnext-with-authを使用します。

// ./utils/withAuth.js
import nextAuth from 'next/auth'
import parseScopes from './parseScopes'

const Loading = () => <div>Loading...</div>

export default nextAuth({
  url: 'http://localhost:5000',
  tokenEndpoint: '/api/token',
  profileEndpoint: '/api/me',
  getTokenFromResponse: (res) => res.id_token,
  getProfileFromResponse: (res) => res,
  parseScopes,
})

Reduxでこれをすべて行うことは不必要に複雑に見えましたが、基本的にはwikiの例に従うことができますが、AuthServiceをアクション(ログインとログアウト)に移動し、UserReducerを使用します。 ただし、サーバーにはlocalStorageがないため、クライアントでのみこれらのアクションを呼び出すことができます。そのため、アクションでそれを確認する必要があります。 最終的に、reduxストアはとにかくwindow置かれます。 したがって、コンテキストを使用する代わりに、ユーザーを自分でwindowにキャッシュすることができます。 reduxが必要ない場合は、 react-broadcast試すこともできます。

最後に、 next/serverが#25に従って出荷されると仮定します。 next-with-authは、ミドルウェアとHOCを使用して、複雑なlocalStorageとCookieを開発者から遠ざけることができます。 トークンの更新も処理できます。

これを試してみることに興奮しています! 必要最低限​​の実装をありがとう:)

@jaredpalmer私は似たようなことに取り組んでいます。 コンポーネントがサーバー側でレンダリングされる場合、 AuthServiceはどのように機能しますか? サーバーはJWTにアクセスする必要がありますが、ローカルストレージからJWTを読み取ることはできません。

@amccloudそうではありません。 それが全体の問題です。 HOCは保護されたルートに<div>Loading..</div>をレンダリングし、トークンを読み取ってcomponentDidMountにリダイレクトするかどうかを決定する必要があります。 希望どおりに機能してサーバー側でレンダリングするには、Nextに#25、または少なくともJWTAFAIKの値を使用してCookieを設定する機能が必要です。

cookie-jsを使用してcookieを設定しましたが、少しハックです。
重要なのは、Cookieを送信しないと、認証されたルートでのnextjsとサーバー側のレンダリングのすべての利点が失われるということです。

@jaredpalmerこれは素晴らしいです! 努力に感謝します。 私は次の日にあなたの例の実装を終了しようとします(または必要に応じてそれを行うのを手伝います)

よ! nextjsとauth0の例をここに公開しました: https
メインレイアウトの概念と、ユーザーが認証されたときにのみ読み込まれる「安全なページ」の概念があります。
ご意見をお聞かせください🎉

@luisrudgeすごい。 私はクローンを作成していくつかの変更を行っていますが、見栄えがします

いいね! 何が欠けていると思いますか? どんな変化を考えていますか?

13:12 -0200の日、2016年11月6日には、 "ダンZajdbandは、" < [email protected] [email protected] >書きました:

@luisrudgehttps ://github.com/luisrudgeすごい。 私はクローンを作成していくつかの変更を行っていますが、見栄えがします

あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信するか、Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687108で表示するか、読み取りをミュートします

1)リンティングにstandardを使用する(したがって、次に構築するすべてのものと一貫性があります)
2)@rauchgによって要求されたマルチタブサポートの追加
3)css部分を簡略化できます

私はあなたにPRを送ります:)

マルチタブサポートとはどういう意味ですか?

13:16 -0200の日、2016年11月6日には、 "ダンZajdbandは、" < [email protected] [email protected] >書きました:

1)リンティングの標準を使用する(したがって、次に構築するすべてのものと一致します)
2) @rauchghttps ://github.com/rauchgによって要求された
3)css部分を簡略化できます

私はあなたにPRを送ります:)

あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信するか、Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687373で表示するか、読み取りをミュートして

2つの開いているタブがあり、1つでログアウトし、もう1つで自動的にログアウトします。

ああ。 すごくかっこいい!

13:21 -0200の日、2016年11月6日には、 "ダンZajdbandは、" < [email protected] [email protected] >書きました:

2つの開いているタブがあり、1つでログアウトし、他のタブで自動的にログアウトします

あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信するか、Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687707で表示するか、読み取りをミュートして

こんにちは@luisrudge私はあなたに変更を加えたPRを送りましたhttps://github.com/luisrudge/next.js-auth0/pull/2

これをしてくれてありがとう<3

ところで、これは結果です:

2016-11-06 11 14 31

@impronunciable @luisrudge素晴らしい実装! Auth0なしで使用したい場合は、。/ utils dir内のファイルを変更するだけでよく、おそらくlock.jsだけを変更する必要があるようです。 すぐに試してみます。 ところで、マルチタブは素晴らしく見えます💯

@ugiacoman passwordless.netを使用して小さなサーバーの実装を開始しました。開始点としてコードを取得する場合は、お知らせください。

@impronunciableそれは素晴らしいでしょう! 私は実際にTwitterFabricのDigitsと同じようなことをするつもりでした。

@impronuncibleパスワードless.netを使用しないことをお勧めします。代わりに、passport-localを使用して、クエリ文字列にメールとトークンを含むリンクをユーザーに送信するだけです。

ありがとう@ impronunciable❤️

@ugiacomanええ、auth0の依存関係を削除するのはとても簡単です。 認証を処理するための個別のAPIが必要なかったため、これを使用しました

@jaredpalmer私の知る限り、#25があれば素晴らしいのですが、ブロックされていませんか? つまり、 getInitialPropsのサーバー側reqにアクセスできるので、 cookie-parserを適用することを妨げるものは何もありませんか? サーバー側の認証とセッション管理は私にとってすべて新しいものです😬

ところで、 localStorageをサーバー側で使用できないことを考えると、Cookieはサーバー側のセッションを持つ唯一の方法ですか? 私は漠然とした記憶を持っていますが、それは最も安全ではないかもしれませんか? しかし、他のオプションはありますか?

@sedubois

クッキーのアプローチは、適切に行われれば非常に安全です。 次のことを行うのはかなり簡単です。

  • httpOnlyフラグを使用します(JavaScriptによるCookieへのアクセスを防止します)
  • 安全なフラグを使用します(httpsリクエストにはCookieのみを設定します)
  • 署名されたCookie(Cookieのソースを確認する)

サーバー上で認証情報に直接アクセスできる場合、レイテンシーの利点も非常に大きくなります。

この例をexamples/に移動する必要があります。

次の方法でnextjsをカスタムエクスプレスサーバーでラップすることにより、同形のCookieにreact-cookieを使用することができました。

const express = require('express')
const next = require('next')
const cookie = require('react-cookie')
const cookieParser = require('cookie-parser')

const app = next({ dev: true, dir: process.cwd() })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express()
  server.use(cookieParser())       // <---- this line

  server.get('*', (req, res) => {
    cookie.plugToRequest(req, res) // <---- this line
    return handle(req, res)
  })

  server.listen(3000, (err) => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})

これにより、サーバー側から認証済みのリクエストを行うことができます。 これは元の箇条書きの問題のいずれにも対処しませんが、クライアントとサーバー間で状態を共有する問題を解決しました。

このようなことをたくさん学んでいる誰かの視点から。 例がauth0のようなサードパーティのサービスに依存していないのが最善だと思います。 ログイン/サインアップフォームを使用し、ReduxとJWTを使用した、より基本的な例を見ると、初心者にとってより有益です。

_バンドル_する予定の例は、オープンソースのNode.jsサーバーAPIに基づいています

https://github.com/iaincollins/nextjs-starterのサンプルスタータープロジェクトにメールベースの認証の例を追加しました

セッションサポート(バックエンドでのエクスプレスセッションとフロントエンドでそれらをキャッシュするブラウザsessionStorage APIを使用)、httpOnly Cookie、CSRFプロジェクション、組み込みのSMTPを使用して電子メールを送信し、デフォルトでSQLLiteに設定されているバックエンドを簡単に変更できます。 実行するために構成は必要ありません。

プロジェクトにはレイアウトページ、カスタムルートもあり、wikiの時計の例が含まれています。 これは認証の最も素晴らしい例ではありませんが、理解しやすく、いじりやすい単純なプロジェクトを簡単に始めたいと考えている人には役立つかもしれません。

JWTの例は良い考えのように思われるという@iamjacksに同意します。

エラー処理を改善し、ユーザーが編集できる簡単なプロファイルページや、Facebook、Google、TwitterのoAuthの例とのパスポート統合などの機能を追加できれば幸いです。 人々がセッション情報をコンポーネントに伝播/公開するためのより良い方法について良いアイデアを持っているなら、私は非常に興味があります。

Example screenshot showing what to expect

それはかなり信じられないほどの@iaincollinsです。 これは2.0のリリースノートで確実に取り上げられます:)

@rauchgありがとうございます! :)

この例では、セッションはクライアントベースとサーバーベースの両方である、つまりJavaScriptの有無にかかわらず(およびsessionStorageのないシステムで)動作し、同じセッションが両方で共有されることを明示的に追加する必要があると思います。

これを達成することは、セッションコンポーネントで少し厄介になります。セッションコンポーネントは、サーバーヘッダーからCSRFトークンを取得するためにreq.connection._httpMessage.locals._csrfのような名前の変数を掘り下げます-'req 'オブジェクトがgetInitialProps()のページに渡されます不思議なことに、Expressで公開されているreqオブジェクトとは少し異なります。これは、通常req.locals._csrfを介してアクセスするためです(ただし、req.sessionは両方で同じです)。

localStorageは安全ではありません。 それをより安全にするための最良の方法は何ですか。 誰でもlocalStorageデータを盗んでブラウザに再配置でき、被害者ユーザーとしてログに記録できます。

@Chathulaそれは真実ではありません。 この議論は間違っています。
誰かがブラウザに物理的にアクセスできる場合、彼らは何でもできます。

これはクッキーにも当てはまります。

cookieベースの秒の問題を取り除く可能性があるため、認証にlocalStorageを使用することは一種の安全です。
しかし一方で、それはSSRに影響を及ぼします。

@arunoda LaravelAPIとNext.jsクライアントでログインを作成しました。 authUseraccess_tokenをlocalStorage内に保存します。 次に、認証によってユーザーがログに記録されているかどうかを確認します。 しかし、それは安全ではありません。 誰かがlocalStorageデータを盗んだ場合。 彼/彼女はそれを使うことができます。

誰かがlocalStorageデータを盗んだ場合。

どのように? 基本的に、彼/彼女はブラウザに物理的にアクセスできる必要があります。 そうすれば、その人は何でもできます。
ですから、それについて心配する必要はありません。

暗号化を使用して、はるかに安全にすることはできませんか?

@Chathulaこれは話題から外れています。 これはNext.jsとはまったく関係がないので、通常のWeb関連の動作を確認したいと思います。

@Chathulaは、上記のスタータープロジェクトで新しいスレッドを開始できる可能性があります。

@アルノダハハ!! 情報ありがとうございます! :NS

@Chathula特定の懸念がある場合は、スタータープロジェクトの問題でさらに話し合うことができてうれしいです。

人々が不必要に警戒するのを避けるために、誤解を正したいと思います。

Web Storage API(つまり、localStorageとsessionStorage)は、httpOnlyが設定されていないCookieのように、同一生成元ポリシー(プロトコル、ホスト名、ポート番号)によって制限されており、「誰でも[それ]を盗むことができる」というのは真実ではありません。 ただし、誰かがアプリケーションのクロスサイトスクリプティングの脆弱性を介してサイトで任意のJavaScriptを実行できる場合は、その人もストアにアクセスできるため、セッション識別子を格納しないでください。

これが、セッショントークン自体がlocalStorage / sessionStorageに保存されておらず、JavaScriptで読み取れないことがわかる理由です。これは、HTTPのみのCookieを介してのみ送信されます(これが、セッションクラスがfetch()ではなくXMLHttpRequest()を使用する理由です-クラスのドキュメントで説明されているように)。

つまり、誰かがアプリケーションのクロスサイトスクリプティングの脆弱性を悪用してWebアプリで任意のJavaScriptを実行できたとしても、ユーザーセッショントークンを読み取ったりエクスポートしたりすることはできません。

これはおそらく、ドキュメントで作業する価値のある重要な違いです。

注:ユーザーデータの追加の暗号化は、レンダリングできるようにアプリが常にデータを読み取ることができる必要があるため、ここでは役に立ちません(したがって、暗号化をレンダリングする説明キーもアプリに保存する必要がありますユーザーデータはかなり意味がありません)。

_UPDATE:先週または2週間で、sessionStorageがタブ間で共有されず、機密性の低いデータを共有するため、セッションストレージではなくlocalStorageを使用するように例がリファクタリングされました。これにより、不要な認証チェックの数が減り、タブ間でセッションステータスの一貫性が保たれます。_

実験中にこのサンプルアプリを作成した人にとっては、おそらく役立つでしょう。

https://github.com/possibilities/next.js-with-auth

このおもちゃのバックエンドに支えられています:

https://github.com/possibilities/micro-auth

ここに展開:

https://next-with-auth.now.sh/

ここのバックエンド:

https://micro-auth.now.sh/

@possibilitiesありがとうマイク! 安全なページを処理するための優れた方法を示す別のマイクロサービスを公開するだけでなく、私が考えていたのは良いプラグマであり、インスピレーションを得るかもしれません。 next.js-with-authリポジトリで発生するアイデアがいくつかあります。

もう少し考えた後、私はおそらく上記の努力を素晴らしい例として保持しないでしょう。 サインアップ/サインインでWeb1.0スタイルを完全に送信するように変更して、サーバー上でHTTPのみのCookieを確立し(XSS経由でJWTへのアクセスを排除)、ユーザーオブジェクトをreqアタッチできるようにします。トークン全体よりも。 これはCSRFの脆弱性の可能性を残しますが、これはXSSよりも軽減するのが簡単だと思います(いいえ?)。 これの良い副作用は、クライアントアプリが宣誓サービスを介してサインインするときにほぼ同じフローを使用できることです。

また、後から考えると、 Page HoCのgetInitialProps内のCookieを解析することで、「ミドルウェア」(したがってカスタムサーバーの必要性)を回避できることがわかります。

@ possibilities'secret 'ページは単なるページであり、webpackにバンドルされているので、/ secretに移動すると、ブラウザに配信されませんか?

ええ、サーバー側のリダイレクトを行うために配線する必要があると思います。

ところで、私はgithubでサインインするという最初のプロジェクトに気を取られてしまいました。 フローは同様ですが、セキュリティにさらに注意を払っています(つまり、XSSを介してoauthトークンが公開されないようにクライアントにシークレットを公開しない)。 それは適切なアプリに縛られていますが、興味があれば、一般的なoauthフローに役立つものに分解することができます。

@possibilities最小限の(しかし適切な)with-authの例を含むPRがあれば、それは素晴らしい助けになると思います🙂私は自分のアプリ(https://github.com/relatenow/)でauthに取り組んでいます関連)が、現在はクライアント側(localStorage)のみです。

@sedubois passwordless.net https://github.com/zeit/next.js/pull/646を使用してそのためのPRを持っていますが、認証サーバーを別の場所に移動します

graphqlを使用するのはどうですか?

Apolloはgraphql認証の例を示しています:

https://dev-blog.apollodata.com/a-guide-to-authentication-in-graphql-e002a4039d1

ここでは、graphqlリクエストを認証していますが、この場合に適合させることができます。

さらに、graphqlは実装とロジックを抽象化できます。 これは、passwordless、auth0、またはその他の必要なものと一緒に使用できます。

@impronunciable参考までに、あなたの例では、@iaincollinsの例を採用してみます。

私の要件は次のとおりです。

  • 安全
  • サーバー側、次にクライアント側の認証
  • Facebookとログイン/パスワードの両方をサポート
  • 認証プロバイダーは簡単に変更する必要があります
  • Graphcoolでユーザーを作成する
  • Graphcoolへの後続のGraphQLリクエストを認証します

それが誰かを助ける場合に備えて、サーバー側の認証を備えた私のアプリがあります🙂

認証はNext.jsサーバーから分離する必要がありますが、他の誰かがそれについてインスピレーションを与えるのを待っています...また、CSRFから適切に保護されているかどうかもわかりません。

これは私がしたことです:

  • ユーザーがログインすると、クライアント側のjavascriptは、認証ベアラートークンを含むCookieをブラウザに設定します
  • 認証されたリクエストを行う場合、サーバー側(next.js)のコードは、ブラウザーのリクエストのヘッダーにあるベアラートークンを読み取り、それを使用してクライアントに代わってAPIサーバーに接続します。

これは、XSS(reactがそれを防ぐために多くのことを行う場合でも)およびCSRF攻撃に対して脆弱ですが、単純でSSRで機能します。

リクエストに追加するだけ

graph.cool + apollo + jwt + auth0 + next.js、その最初の4つの部分はhttps://github.com/graphcool-examples/react-apollo-auth0-exampleですでに実行されてい

あなたの例の@baluptonは、ユーザーがまだ接続している間にトークンが期限切れになるとどうなりますか、セッションはちょうど終了しますか、更新されますか?

@nmaroわからない、私が書いたものではない-あそこに聞いてみるのが一番

私自身のアプリでは、next.jsとauth0を使用して認証を行い、次にベアラートークンを検証するzeit / microAPIサーバーを使用します。

2月中にオープンソース化できるはずです。

next.jsが従ってきたのと同じ哲学(1つのことを実行し、それをうまく実行する)に従って、ノード用の拡張可能なユーザーアカウントシステムのスケルトンを開発しました。 ここで哲学を参照してください: https

githubプロジェクトはここにあります: https

目標は、node.jsで非常にうまく機能するアプリケーション構造である、個別のマイクロサービスとして使用するのに理想的な、拡張可能な独立した認証+ユーザー管理サービスを提供することです。

電子メールとパスワードの認証の例は次のとおりです: https
FacebookとGoogleauth(ooth-facebookとooth-google)のパッケージはすでに用意されており、それぞれpassport-facebookとpassport-googleに基づいて簡単に実装できるはずです。

next.js統合の例をできるだけ早く投稿します。 気軽にディスカッションに参加して貢献してください。

プラグについては申し訳ありませんが、それはより大きな利益のためです-私はノードのための良い解決策はまだないと本当に信じています、そしてこれはそのようなことを望むかもしれない人々のちょうどいい聴衆です。 平和

一方...これは、書き込み操作のためだけにJWTトークンによる認証を必要とするgraphqlAPIの例です。 お好きな認証方法でお気軽にご利用ください:)

https://github.com/nmaro/ooth/tree/master/examples/graphql-api-with-auth

https://nextjs-starter.now.shを更新して、oAuthサポートを追加しました。

screen shot 2017-02-10 at 05 03 19

  • (以前と同様に)エクスプレスセッションとともに、oAuthにPassportを使用します。
  • Facebook、Google、Twitter + oAuthがサポートされており、簡単に追加できます( AUTHENTICATION.mdおよびroutes / auth-passport.jsを参照)。
  • 電子メールサインインの使用に応じて、ユニバーサルクライアント/サーバーセッションシステム(CSRFトークン、HTTPのみのCookieによるXSS保護、Mongo、SQL DB、RedshiftなどをサポートするORMレイヤー)を使用します。
  • 開発者ポータルでoAuthを構成した経験を報告できます(奇妙なエラーが発生し、デバッグが困難です)。

oAuthの性質(db + sessions + passportとエラー処理は緊密に連携する必要があります)、およびセッションはクライアントとサーバーの両方で動作する必要があり、それがユニバーサルレンダリングでどのように機能するかは、次の場合に一度にラップアラウンドすることを少し意味します。何が起こっているのかを理解しようとしていますが、クライアントロジックにはoAuth固有の構成がないため、それほど面倒ではありません。

認証だけを別の例に分けて喜んでいますが、それほど小さくはないと思います。 他の誰かがしたいのなら、素晴らしい。 おそらく、ある時点で例にもう少し追加します(アカウント管理ページなど)。 おそらく、ドキュメントにもっとリンクするのが良いでしょう。

素晴らしい仕事! 認証を分割してnext.jsリポジトリに追加できれば、それは素晴らしいことです:heart:

私もそれを行うことができます👍🏻

次の2週間ほどは時間がないので、誰かがやりたいのならそれは素晴らしいことです。

それをリファクタリングして、モジュール(ログインボタンやサインインフォームなどの単純なコンポーネントを公開して埋め込む)に縮小できるかどうかを確認し、以前のクライアント側のみの非常に優れた例からインスピレーションを得たいと思います。 @impronunciableによる。

更新:私は実際に去っています、それが私ができない理由です、しかし私が戻ったとき、私はそれをすることを見てうれしいです!

auth0 / reactクイックスタートガイドにいくつかの変更を加えましたが、 lock.show()を呼び出すと、アプリから次のような苦情が寄せられます。

キャッチされないエラー:addComponentAsRefTo(...):ReactOwnerのみが参照を持つことができます。 コンポーネントのrenderメソッド内で作成されていないコンポーネントに参照を追加しているか、Reactの複数のコピーがロードされている可能性があります

@iaincollins @timneutkensあなたの例に関して、私が間違っている場合は私を訂正してください。

この例では、httpOnly Cookieを使用してセッショントークンを保存し、JavaScriptインジェクション攻撃(XSS)に対して安全にしています。 次に、CSRF攻撃からも保護するために、csrfトークンをローカルストレージに保存するという問題が発生します。

このテクニックの組み合わせが物事を安全にし、ユーザー/開発者を誤解させる可能性があるという根本的な仮定があります。 攻撃者は引き続きページ(XSS)にJavaScriptを挿入し、csrfトークンを読み取り、それを使用してAPIへの認証済み(Cookie)リクエストを実行できます。 READMEで言及する価値はありますか?

こんにちは@davibe

残念ながら、現在、セッションCookieと個別のローテーションCSRFトークンよりも技術的に優れたアプローチはありません。そのため、実際には別の方法がないため、モデルに大いに満足していると言わざるを得ません。 (実際の実装は常に改善できる場合でも)。

ブラウザのフィンガープリントを追加できます。セッショントークンがより頻繁にローテーションする可能性があります(今は自動であるかどうかは忘れます)。CSRFトークンはparamではなくヘッダーにすることができます。Cookieは実際には本番環境でのみSSLである必要があり、追加できます。サインイントークンの有効期限ですが、AFAICSには、セキュリティモデルに関する限り、改善の余地がかなり限られており、誰かが好きなコードをアプリに挿入できる場合に、さらに保護を与えるものは何もありません。 しかし、リポジトリの改善のための問題として、これらのことを気軽に提起してください。

アカウントステータス変更オプション(現在はありません)がある場合は、実行する前にCAPTCHAを使用して、許可なくサーバーに変更を加えることをより困難にすることができますが、この例で発生するのは、ユーザーがサインインできることだけです。そして、それは現在範囲外です。

セッショントークンをローカルストレージに保存すると、安全性が著しく低下し、仕様での使用目的に反するため、個人的には賛成できません。CSRFプロジェクションがないため、物事が単純化されることを感謝していますが、おそらく人々は非常に簡単なので、その例は必要ありません。非常に扱いにくいため、提供しようとしただけです。 :-)

私もそれがどれほど厄介であるかを嫌い、それをモジュールに変えようとすることをあきらめなかったという点で、私はあなたと完全に一緒です。

うーん..わかりました。
この問題は私にとって非常に役に立ちました、ありがとう。

これはAuth0の視点ですhttps://auth0.com/blog/cookies-vs-tokens-definitive-guide/
彼らは基本的にクッキーを避けることを提案していますが、それは私が思う最初のページのロードでSSRを除外するでしょう。

こんにちは、みなさん!

また、next.jsを使用した認証にも取り組んでおり、この問題からのコメント、特に@davibe + リポジトリと@timneutkensPRは非常に役立ちました。

私のソリューションは次のことを行います。

  • ログインに成功すると、私のreduxレデューサーはreact-cookieを使用してトークンとユーザーデータをCookieに保存します。
  • その情報を必要とするページ/コンポーネントは、 @ timneutkenswith -session.jsのような高次のコンポーネントにラップされます。 SSRの場合、トークンはctx.req.headers.cookieで使用できます。それ以外の場合は、ブラウザードキュメントからトークンを取得します(react-cookie loadメソッドを使用します)。
  • トークンを取得したら、リクエストを行うたびにBearer / Authorizationヘッダーにトークンを設定できます。

Dockerコンテナで独自のJWTトークン認証マイクロサービスを実行していると便利です。
おそらく、with-authの例の一部として単純なJWTサービスを提供する方が簡単でしょうか? したがって、server.jsをハッキングすることを回避し、next.jsに組み込まれたホットリロード、ssr、およびルーティングの利点を失う可能性がありますか?

また、このアプローチがCSRF / XSSの観点から安全かどうかもわかりません。 コメントは大歓迎です。

これまでに行った素晴らしい仕事に感謝します。 私はこのプロジェクトの大ファンです!

@jcsmesquita zeit.coでauthを実装する方法と同様に、Next.jsからすべてを分離した新しいバージョンの例に取り組んでいます。

これは便利なようです: https

@subsumo言及してくれてありがとう、NAPは私のものであり、Web経由の認証は@iaincollins nextjs-starter基づいており、ネイティブクライアントのログインをトークンで反応させます。

@timneutkensあなたが取り組んでいるソリューションでは、別のサービスに対して認証することができますか?

私は現在の認証例のプルリクエストを見てきましたhttps://github.com/zeit/next.js/pull/1141
next.jsサーバーに対してのみ認証許可しないように思われます。

つまり、next.jsサーバーと実際のアプリAPI(RESTやGraphQLなど)を分離する場合、クライアントとサーバーがAPIに対して認証できるようにする必要があります。 私はこの解決策が本当にあなたを助けるとは思わない。

流れを考えました。

エンティティ:

  • クライアント(C)
  • Next.jsサーバー(S)
  • API(A)

目標は、3つのCookieベースのセッションを確立することです。

  1. CS
  2. CA
  3. SA

セッション1)は、クライアントがサーバーを認識するためのものであり、2)3)は、クライアントとサーバーの両方がそれぞれのセッションを使用してAPIに個別にアクセスできるようにするためのものです。

これがフローです。

  1. CSは簡単に実行でき、認証は必要ありません
  2. CAは認証を使用して実行されます(たとえば、ユーザー名/パスワードを使用)。 さらに、JWTが提供されます
  3. クライアントはサーバーにJWTを提供し、それを破棄します
  4. SAはJWTで実行され、その後破棄されます

あなたの意見は何ですか? もっと簡単な方法はありますか? 代わりに、APIをnext.jsサーバーと結合したままにして、1つのセッション(CS)のみが必要になるようにする必要がありますか?

@rauchg簡単に呼び出すことはできませんが、これはnext.jsが進むべき方向についてもあると思います。「ユニバーサルフロントエンド」として、データを提供するAPIとは別に実行する必要がありますか? はいの場合、これを正しく行う必要があります。

@timneutkensあなたが取り組んでいるソリューションでは、別のサービスに対して認証することができますか?

そうです。 Next.jsで他のものを修正するのに忙しい。 できるだけ早くそれに戻ります。

私は自分のアプリのgithub-auth固有の部分をかなり消化しやすい例に分解しました。 一部の人にとっては興味深いかもしれませんし、コードやフローに関するフィードバックをお待ちしています: https

更新:サンプルアプリを、次のアプリに「ドロップイン」できる再利用可能なコンポーネントのセットにリファクタリングしました

フォローアップ: ooth統合作成しました。

https://medium.com/the-ideal-system/ooth-user-accounts-for-node-js-93cfcd28ed1a#.ykoj1dhil

これは、既存のアプローチ、つまりnext.jsサーバーの認証

@timneutkensその面で何か進歩はありますか?

github authサンプルアプリを、次のアプリに「github authをドロップする」ために、再利用可能なデコレータとページコンポーネントのセットにリファクタリングしました。 コードと機能のフィードバックを歓迎します。 https://github.com/possibilities/next-github-auth

ここでボードを特定し、これを次のより一般的な認証フレームワークに進化させ続けることは興味深いかもしれません。

@timneutkens
pingを実行して申し訳ありませんが、これについて何か進展はありましたか? next.jsで認証を適切に設定する方法がわかりません。

@kolpav私はそれにいくつかの作業を行いましたが、現在は他のものでいっぱいです😥これは次の優先順位リストでかなり高いです😄

next.jsアプリで認証を実現するための明確で十分に文書化された安全な方法は、フレームワークとして成功するために重要です。

認証のないWebを最後に作成したときのことを思い出せません。
私が想像するほとんどの人のように、私も残りのデータのために私のバックアップに安全な呼び出しをしたいので、JWTは明白な解決策のようです。

しかし、問題とPRの間には非常に多くの議論があり、どこから始めればよいのかわかりません。

@timneutkens
かっこいい👍他の人にとって非常に価値があると思います。

@camstuart @kolpav貢献者@ jaredpalmer@ luisrudge@ impronunciable@ possibilitiesおよび私によるJWTおよびHTTPCookieの両方を使用するoAuthおよび電子メールベースの認証のサポートを含む、上記のいくつかの優れた実用的な例があります。

いくつかのリンクを強調するには、チェックアウトしてください。

(マイクロ認証の例は良かったですが、更新する必要があると思います。)

セッションストアコンポーネントやサーバーロジックの分割など、追加のコメンテーターが上記でコメントした、さらなる改善の余地があります。 そして、ティムが取り組んできたものをさらに単純化する例。

認証のシンプルさはユニバーサルアプリにとって難しい領域ですが、上記の例を実行するか、デモを直接試してみて、それほど大騒ぎせずにどのように機能するかを確認できるはずです。

@iaincollinsそれは素晴らしい例です。 しかし、(たとえば)スタータープロジェクトをどのように使用できますか? だから私は自分のアプリを構築したい場合。 このリポジトリのクローンを作成する必要がありますか? または、スタータープロジェクトからチャンクごとにコードを自分のコードに「コピーアンドペースト」する必要がありますか?

スタータープロジェクトが更新される場合-私は何をすべきですか?

@iaincollins
特にあなたの良い例。
しかし、それでも、承認のzeitシールが付いた認証の例を見たいです😄すべての目が一方向を向いているので、エラーや間違いが見過ごされることはありません。 今のところ、私は自分の有効な認証を持っていますが、それがどれほど安全かはわかりません。

@kolpavに同意し

GraphQLで認証を簡単に処理できるスタックを作成しました: https

@salmazov例やスタータープロジェクトで何が起こっているのかを理解するための便利な方法を見つけました。それをフォークして、機能に関連するコードだけが残るまで、関係のないものを

@kolpav @camstuartこのスレッドには、いくつかの一般的な誤解やトレードオフを

@iaincollins何かをリンクする

こんにちはみんな:)

質問があります。次に読んでいたのは、localstorageからjwtを使用した認証のトークンを取得できないことです。

レンダリング用のサーバーがある場合は、サイトの最初の請求と次の請求だけを行います。 そして、API用に別のサーバーがあります。 これは、クライアントからユーザー/パスを受け取り、jwtを提供します。 どの場合、サーバーでトークンを取得する必要がありますか?

レンダーサーバー(次)にトークンが必要なのはなぜですか?

クライアントがトークンをAPIサーバーに送信しない場合、APIはデータを提供せず、ユーザーは個人情報を取得できません。 トークンをレンダーサーバーに送信する必要がある理由がわかりません。

@kamilml

これは役立つかもしれません。 一般に、2つのオプションがあります。

  1. NextサーバーにJWTを提供します(おそらくCookieを介して)。 これにより、Nextサーバーがクライアントに代わってAPI呼び出しを行うことができます。 サーバー側の完全なレンダリングが重要な場合は、これが必要になります。

  2. JWTをクライアントのローカルストレージに保存し、Nextサーバーにアクセスを許可しないでください。 この場合、API呼び出しをサーバー側でバイパスし、クライアント側の読み込みが完了するまで完全なレンダリングを延期することができます。

これを再開して申し訳ありませんが、このスレッドに2セントを追加し、最初のR&Dがこの領域でどのように展開されているかを考えました。 コード例が少なく、より高レベルのフロー。

まず、コンテキストとして、私たちのアプリのほとんどはすでにSymfony 3(PHP)で構築されており、ハイブリッドエクスペリエンスのためにVueを使用しています。 サーバーはラッパーページをレンダリングし、アプリが取得できるようにアプリデータを__INITIAL_STATE__に割り当てます。 これにより、Symfony(SEO用)でマーケティングページをレンダリングするか、JS経由でデータをフェッチしてよりSPAっぽい感じを提供することにより、他の領域でSEOではなくUX / UIを選択するかを決定しました。 また、すべてのページがバイナリのパブリック/プライベートであるとは限りません(いくつかの例で見たように)。 一部のページはデフォルトで公開されており、認証された場合はレンダリングが異なります。 サイトの一部にSPAを使用することを検討していましたが、多くの実用的な方法で、UX / UIが悪化していました(TTIの低下、プログレスバーなど)。 さらに、FOUCを導入してテキストを2回(Symfonyを介して1回、JSコンポーネントとしてもう一度)レンダリングしない限り、SEOの問題は解決されません。

SSR /ユニバーサルJSを入力してください...

私の場合、私がしたことは、 HttpOnly UJSSESSID cookie(名前を作成)を作成してPHPSESSIDロジックを模倣し、値をユーザーの値に設定することUJSSESSID JWT。 Symfonyアプリは、ユーザーがサイト内を移動するときに、各ページリクエストでこれを渡します。 ユーザーがUJSページにアクセスすると、それらのアプリのサーバー側がリクエストでCookieを受け取ります(ブラウザーの組み込み動作に従って)。 UJSSESSID Cookieが設定されている場合、アプリはAPIを呼び出してユーザー情報を取得します(たとえば、 Authenticationヘッダーを介してトークンを渡すことで/api/v1/users/me )。 残りの呼び出しは、同じトークンを使用してAPIを介して行われます。 SymfonyのログアウトメカニズムはUJSSESSIDクッキーをクリアします。 次回UJSアプリが読み込まれると、ページが匿名ユーザーモードでレンダリングされます。 参考までに、SymfonyとUJSのページルーティングはApacheのProxyPass介して行われます。 LocalStorageは使用されません。

最終結果は、ユーザーがクライアント側JSを備えたPHPであるいくつかのページと、UJSであるいくつかのページにいるシームレスなUXです。 これにより、A / Bテストを実行し、サイトを繰り返し更新することができます。すべての人が最初から始めるわけではありません:)

これは共生PHP / UJSのために少し複雑ですが、APIまたはNode.jsサーバーミドルウェア(Express、Adonisなど)を使用した完全なUJSソリューションでも同じ原則を使用できます。 PHPページリクエスト( HttpOnlyフラグ)を介してUJSSESSID Cookieを設定する代わりに、ユーザーにSPA / UJSを介してログインさせ、そこでCookieを設定します。 してはいけないことは、アプリを使用してJWTをデコードするか、 client_secretを必要とするサードパーティの呼び出しを行うことです。 そのためにサーバー上にとどまるミドルウェアを使用してください。

それが誰かを助けることを願っています。 私が見た他の例は、私には少しペトリ皿でした。

@jaredpalmerその実装に感謝します、私はそれを試しました、ただすべてのコードをコピーして貼り付け、dashboard.jsを次のような私のindex.jsに置き換えました:

const index = () =>
  <div>
    <span>WoooHoooo</span>
  </div>

export default withAuth(index)

withAuth hocで、サインインページにリダイレクトするように変更しました。
ただし、サインインページにリダイレクトする前に、インデックスページのコンテンツが少し点滅します。 :NS

この問題の状況はどうなっていますか? 😇

これは、議論全体を読んでいる新しい人々にとっては少し圧倒されます。 ここで非常に基本的な認証を実装することにしました。 2ページ(インデックス、ログイン)、およびカスタムサーバーのみ
https://github.com/trandainhan/next.js-example-authentication-with-jwt

基本的に、すべてのリクエストのヘッダーにあるトークンをチェックするための認証ミドルウェアがサーバーにあります。 jwt-tokenはCookieに保存されます。 これは非常にシンプルでわかりやすく、非常にうまく機能します。

@trandainhanシークレットトークンを使用してCSRF攻撃を防ぐPOSTエンドポイントを追加できますか?

@sbkingCSRF攻撃によって保護されたエンドポイントの例でソースコードを更新

これは使用する準備ができていますか😬?

誰かがredux-auth-wrapperで認証を試みましたか?

みなさん、こんにちは! 過去数か月にわたって私は作成し、現在は洗練されています

  • oothと呼ばれるnode.jsの汎用ユーザーアカウントライブラリ: https
  • 最小限のボイラープレートを備えたnextand oothに基づくスターターライブラリ: https

それは特徴です:

  • メールアドレスとパスワードでの登録
  • メールアドレスまたはユーザー名とパスワードでログイン
  • ユーザー名の設定、パスワードの変更、確認メールの再送信が可能なアカウントページ
  • パスワードを忘れた/パスワードページをリセット
  • メールページを確認する
  • MongoDBにリンクされた基本的なGraphQLAPI(1ファイル、簡単に削除できます)
  • 最小限のボイラープレート(可能な限り多くのロジックがライブラリにカプセル化されています)

ここでライブデモをチェックしてください//staart.nmr.io/

私は主に、ラピッドプロトタイピングのために、外部サービスに依存しないシンプルで機能するアカウントシステムを備えたアプリケーションをすばやく開始するためにそれを行いました。 結果にはとても満足しています。 私はこれらのライブラリを使い続けて維持するつもりなので、確立されたアカウントシステムとノードのUIがまだ不足していると感じたら、試してみてください。

@trandainhanありがとう、それは本当に素晴らしい例であり、多くの人々にとってはるかに簡単であり、多くのシナリオで機能します。

nextjs-starterの現在のロジックを適応させて、代わりに安全にこのようなものを使用できるかどうか、また、実際のユースケースのエクスプレスセッションロジックと互換性があるかどうか(使用するなど)について考えます。最初のログイン時に付与されたトークンを保持および追跡するためにサーバーが必要なGoogleoAuth APIなど)。

それが可能かどうかはまだわかりませんが、可能であれば、人々にとってははるかに簡単です。

そうでない場合は、さまざまなオプションを人々に説明するために、少なくともどこかに書いておく価値があります。

@trandainhan :login.jsに<Link href="/">Home</Link>を追加し、生成されたリンクをクリックすると、ログインせずにindex.jsにアクセスできます。この例でこれを修正する方法を教えてください。

@iaincollinsここにあるほとんどのソリューションは、oauthサービスに対して認証されています。 JWTに依存するAPIに対して認証するための良い解決策はありますか?

@paulwehner @trandainhanはサーバー側の認証ルーティングしか処理していないため、

@ carlos-peru内部では、Linkは実際にnext / routerを使用して、ブラウザの履歴に新しいパスをプッシュします。 ほとんどのものはブラウザによって処理されるようですが、サーバー側のミドルウェアについてはここでは何もしません。 これまでのところ、URLを変更するたびに、独自のLinkコンポーネントを作成し、他のことを行うことしか考えられません。

@ carlos-peruいつでもカスタムサーバーを使用して、ルーティングを完全に制御できます。

@trandainhanと@kolpavに感謝します! 週末を過ごした後、理解が深まりました。 また、jwtトークンをCookieに保持するHOCに依存するソリューションを実装して、サーバーとクライアントの両方がAPIを使用できるようにしました。

@nmaro next.jsのウェブサイトとアプリ(react-native)用のJWT認証を備えたバックエンドがあります。

そう。 次のモデルでは、クライアントがFacebookトークンを取得し(ユーザーがFacebookログインを受け入れる)、クライアントがバックエンドにトークンを送信して、ユーザートークンを確認および検証すると思います(node-jsバックエンドのpassport-facebook-token) 。 次に、トークンに問題がない場合、バックエンドはバックエンドで生成されたJWTをクライアントに送信します。

問題? あなたのツールはフェイスブックとグーグルからキーを取得できますか? 私はhello.jsを使用していますが、next.jsと互換性がなく、世界中でpassport-facebookが使用されています。 APIサーバーはWebクライアントおよびモバイルアプリと互換性がある必要があるため、これは大きな間違いだと思います。

ありがとうございました

PS:あなたのSlackチャンネルで招待状を取得できません。

@hmontes here - oothプロジェクト(ノードのユーザーアカウント、特にnext.js)のslackチャネルへの招待は気軽に参加してください。 Oothはpassport-facebook-token(passport-facebookではなく)とpassport-google-id-tokenを使用しており、これで問題が解決すると思います。

@nmaro私はあなたのプロジェクトを手伝いたいです。 passport-facebokとpassport-google-id-tokenを備えたGraphqlのバックエンドもあります!!!

しかし。 next.jsでfacebook / googleクライアントに接続するための互換性のあるパッケージを知っていますか?

クライアント側では、ここで使用したのと同様のパターンを使用できます:https: //github.com/nmaro/staart/blob/master/packages/staart/src/components/login-facebook.js https:// github。 com / nmaro / staart / blob / master / packages / staart / src / components / login-google.js
oothClient.authenticate代わりに、認証ルートにPOSTリクエストを送信するだけです)。

@timneutkensは、最小限のwith-oothの例を使用したPRを歓迎しますか?

あなたの例では@nmaro 。 componentWillMountの代わりにcomponentDidMountを使用するのはなぜですか?

Googleログイン用のHoC(プロバイダー)コンポーネントを作成しています。

componentWillMountはクライアントでのみ呼び出されますか? その後、それは大丈夫なはずです。

オーケー。 例をありがとうございます。 最後に、ソーシャルメディアで認証を実装できます。

最後の質問。 access_tokenとrefresh_tokenを作成し、localStorageに入れてデータを保存したいと思います。

これをnext.jsのどこに置いて、ページが更新されたときにログインを確認できますか? create-react-appで、それをindex.jsに入れます

...
import { loginUser } from './actions'
...
let accessToken = localStorage.getItem('access_token')
let refreshToken = localStorage.getItem('refresh_token')

if (accessToken && refreshToken) store.dispatch(loginUser({accessToken, refreshToken}))

ReactDOM.render(
  <ApolloProvider store={store} client={client}>
....

ありがとうございました

oothでは、Facebookトークンを保存せず、パスポートで1回だけ使用してから、通常のCookieベースのユーザーセッションを作成します。

ああ。 オーケー。 セッションの代わりにJWTを使用しています。 そこで、access_tokenをバックエンドに送信し、トークンがサービス(google、facebook)で有効かどうかを確認してから、ユーザーがアプリに存在するかどうかを確認して、JWTを送り返します。

ありがとうございました :)

JWTをローカルストレージに保存するのは危険です(XSSのため)。すべてが1つのサーバー/ドメインにある場合はCookieとして送信する方がよいため、クライアントのJavaScriptコードはJWTを取得できませんが、ブラウザーはJWTを送信します。 JWTはCookieとして自動的に実行されます。 JWTには注意が必要です(上記の長い説明を参照)。そのため、私はセッションを使用しています。

JWTを使用するのは、oothが外部認証マイクロサービスとして使用されている場合のみです(Cookieは同じドメインでのみ機能するため)。それでも、JWTを1回だけ使用してサーバーとのセッションを作成するため、クライアントのどこにも保存されません。 。

JWTセキュリティを強化するには、更新トークン(oauth2から取得)を使用できます。

モバイルアプリはCookieを処理できますか?

@nmaroオーケー。 私はあなたの言う事が分かります。 エラーでごめんなさい。

JWTトークンをCookieに保存するためのチュートリアルまたはコードはありますか? https://github.com/zeit/next.js/blob/master/examples/with-firebase-authenticationを探しています

いいえ、申し訳ありませんが、私はそれをしませんでした。

@hmontes @nmaro
私は自分でこれを書きましたが、役立つかもしれません:
https://github.com/malixsys/mobazoo

ねえ@malixsys共有してくれてありがとう。 あなたのコードから私が理解していないこと:API_BASE_URLを外部の権利に設定するように思われますか? そのAPIに対して認証すると、Cookieベースのセッションが開始されると思いますよね? しかし、next.jsサーバーが別のドメインにあると仮定して、そのCookieをnext.jsサーバーに転送するにはどうすればよいでしょうか。

ああ、なるほど、同じプロセスで/ auth / signinを設定しました。 さて、それは基本的に私がnext.js / staartでoothに使用したのと同じアプローチです。

実際にはありません。まだ混乱しています。/auth/signinでJWTを返しますが、クライアント側では何もしません。 後で「getUserFromCookie」を実行しますが、Cookieをどこに設定したかわかりません。

@nmaro最初は基本的なログインがユニバーサルで
それはすべて私のTODOリストにあり、PWAがあります。
遠慮なく問題を開くか、ここで私にpingしてください...

@nmaro cookieはここでsaveUser()設定されています: https

この問題が解決したことは知っていますが、解決策を示したいと思います。
https://next-auth.now.sh/
zeit.coのウェブサイトに少し似ていると思います

4月9日

私はそれにいくつかの作業を行いましたが、現在は他のものでいっぱいです😥これは次の優先順位リストでかなり高いです

9月22日#2974

公式の認証例をまもなくリリースする予定ですが、これを別のリポジトリとしてリリースできますか? Thaaaanks!

@timneutkens

こんにちは、これについてもう一度バグを報告して申し訳ありませんが、公式の認証例のステータスはどうですか? それは間違いなく私が見たいものであり、この号の他の人たちのコメントの数から判断することもできます。 それで、それは優先順位リストでどれくらい高いですか、そして私たちは私たちの希望を上げる必要がありますか? 😄

こんにちは@kolpav 、彼らは

最後に、要望の多かった例(ユーザー認証など)、Next.js内部のドキュメントの改善、小さな機能とバグ修正を追加します。

https://zeit.co/blog/next-canary#the -roadmap

@babenzeleそれは素晴らしいニュースです。 私はそれを逃したに違いありません😅

Next.js 5の開発について、どこで最新情報を入手できますか? 私は現在auth0を統合していますが、公式のnextjs認証パス/例があれば素晴らしいと思います

Next.jsは、JWT / cookies / localStorage(または、安全でXSS / CSRFから保護されている限り、それらの組み合わせ)を使用した公式のローカル認証の例を切実に必要としているようです...私は数週間かけてPassport.jsローカル戦略を備えた別のExpressAPIサーバーを使用してこれを考え出します。 ステートレスリクエスト用にcookie / localStorageでJWTを試しました。また、最終的にJWTとステートレスをあきらめた後、エクスプレスセッションミドルウェアからのセッションIDを含む通常のcookieも試しました。 エクスプレスセッションの動作方法が原因で、Express APIサーバーで追加のセッションが作成されるという問題が発生しました(saveUninitialized:falseで試してみました)。 Next.jsアプリでExpressコードをserver.jsに移動することを検討しましたが、実際には別のサーバーにしたいです。 また、私の実装はXSS / CSRFやCookieのハイジャックから安全ではないと確信しています。 ローカル認証/ログインのベストプラクティスをカバーする公式の例、または複雑さを処理するNext.jsの一部としての公式モジュールが必要です!

Next.js 5.xとその他の例を待っている間、 https: //nextjs-starter.now.shを確認することをお勧めします。https://nextjs-starter.now.shは引き続きアクティブに維持されており、Express、Express Sessions、CSRFでNext.jsを使用しています( CRSFトークン)、XSS(セッショントークンのHTTPのみのCookie)、およびPassportJSを使用してoAuthとEmailをサポートします。

私は実際に認証コードをモジュールにリファクタリングしている最中です。これにより、Next.jsプロジェクトに使いやすい方法で認証を簡単に追加できるようになります。 このモジュールを使用すると、スタータープロジェクトの例から大量のコードをコピーしなくても、任意のデータベースで簡単に使用できるようになります。 今週はそれで終わらせたいと思っています。

参考までに、「Double Submit Cookie」メソッドは、シンプルで安全なアプローチを探している場合に、CSRF保護を追加する簡単な方法を提供します。

localStorageのJWTの問題は、クライアント側のJavaScriptから常に読み取り可能であるため、信頼できないコンテンツ(ユーザーが送信したコンテンツや広告など)がある場合は、XSSを介したセッションハイジャックのベクトルです。

セッショントークンにHTTPOnly Cookieを使用する場合(またはHTTP Onlyのトークン値を持つJWTのようなものを使用する場合(またはJWT全体を暗号化し、サーバー上のHTTP Onlyトークンを使用して復号化する場合)、セッションは可能な限り保護されますなれ。 理想的には、セッショントークンはクライアント側のJavaScriptを介して読み取り可能であってはならないという考え方です。

もちろん、多くのサイトではHTTPのみのCookieを使用していません。これは、シングルページアプリにとっては面倒であり、常にフロントエンドに認証ロジックを含める必要があるためですが、それでも理想的なアプローチです。

もう1つのオプションは、 https://github.com/nmaro/oothです。これはアクティブに維持されており、すでにパッケージで提供されており、いくつかの本番アプリで使用されています。

@iaincollins Next.jsスタータープロジェクトをダウンロードして、調べ始めました。 重要なセキュリティ関連(XSS / CSRF)の部分を分離してアプリケーションに統合するか、別のモジュールが完了するまで待つ必要があります。 そのモジュールの開発を追跡できる場所はありますか?

こんにちは@ kelleg1

別のモジュールがnext-authモジュールとして公開され、他のプロジェクトでの使用が容易になりました。 使用方法を示すサンプルプロジェクトが含まれています。

さらに参照するために、 nextjs-starter.now.shプロジェクトもnext-authを使用するようになりました。これにより、スタータープロジェクトのコードが大幅に簡素化され、新しいoAuthプロバイダーのサポートを追加したり、さまざまなデータベースで使用したりすることがはるかに簡単になりました(例ではまだMongoDBを使用していますが)。

それでもまだやや複雑なので、既存のアプリをお持ちの場合は、リファレンスとして使用する方が簡単かもしれませんが、そうであれば、お役に立てば幸いです。

注意:CSRFは、現在でもかなり緊密に結合されています。 luscaを使用するため、res.locals._csrfが設定されていると想定しますが、CSRFライブラリが異なれば使用するプライベート変数も異なります。

誰もがそのまま使用するよりもさらに複雑に使用できることを感謝しますが、少なくとも今では、認証コードが最終的にモジュールに分離されているため、リファクタリングを開始できます。 時間の経過とともに(さまざまなデータベースのデフォルトハンドラーとoAuthの構成を簡単にして)使いやすくしたいと思っています。

@iaincollins next.jsへの唯一の依存関係はhttps://github.com/iaincollins/next-auth/blob/master/index.js#L342のようです? もしそうなら、libをnext.jsに依存しないようにするのは素晴らしいことです。

@sedubois完全に同意します!

ここではなく、GitHubリポジトリの問題についてはおそらく良い議論ですが。 🙂改善、簡素化、より一般的な方法を提案したい場合は、コラボレーションしたいと思います。

(nextでできるだけ使いやすいものを用意することは依然として主要な目標ですが、次の特定の焦点を絞ったオプションで終わったとしても、排他的である必要はないと思います。)

@timneutkens nextjs 5のリリースおめでとうございます。近い将来、公式のローカル認証の例がexamplesフォルダーに追加される予定ですか? それとも、これは後のリリースでまだ作業中のものですか?

Oothには、 next.js認証の詳細を含む包括的なドキュメントがあります。

@jaredpalmer私はあなたのアプローチが好きです、私はあなたの実装の一部をコピーしました。 ただし、 getUserメソッドは安全ですか? 誰かがローカルストレージ内の文字列を手動で変更した場合、アプリケーションがこれに依存するのは賢明でしょうか? トークンのJWTパブリック部分を毎回デコードし、そこからユーザーの状態を読み取るメソッドに変更する方が理にかなっていますか? そうすれば、JWTの性質上、この状態をより信頼できます。 あなたの意見は何ですか?

あなたはそれをクッキーに保存するべきです。 Nextがカスタムサーバーをサポートする前に書いた。

@jaredpalmerそれについてもっと教えてもらえますか? ローカルストレージではなく、すべてをCookieに保存する必要がありますか? あなたのHOCも違いますか? サーバー側で保護されたWebサイトをレンダリングするためにgetInitialPropsメソッドを使用できるようになったということですか?

_あなたが保存について話しているのがローカルストレージ/ Webストレージの機密データである場合_:

「Webストレージを使用して機密データを保存しないでください。Webストレージは安全なストレージではありません。ネットワーク経由で送信されないため、Cookieよりも「安全」ではありません。暗号化されていません。安全またはHTTPのみのフラグがないため、これはセッションやその他のセキュリティトークンを保持する場所ではありません。」

ログイン後にCookieにトークンを設定します。 cookie-jsを使用します。 次に、サーバーでエクスプレスCookieパーサーを使用して、getreq.headers.cookies.myTokenまたは同等のものを確認できるようにします。 hocのgetInitialPropsで、reqが存在するかどうかを確認してから、req.cookiesからトークンを取得します。それ以外の場合は、Cookies.get( 'mytoken')からクライアントでトークンを取得します。 この時点で、クライアントとサーバー上のトークンにアクセスできるようになります。 次に、fetch / axiosラッパー/インスタンスを作成し、それをgetInitialPropsのnextのctxとマージして、すべてのページが認証された同形リクエストを作成できるようにします。 また、ユーザーをその場で利用したい場合もあります。 したがって、どこでもそれを繰り返す必要はありません。 withUser(withTeam(Page))のような一般的なエンティティが必要な場合は、さらに多くのホックを作成できます。

getUserは悪い考えです。トークンのみを保存する必要があります。

@jaredpalmer私はほぼそのようなアプローチを構築し、すべてが正常に機能しています。 私が今解決しようとしている問題は、トークンを更新する方法です。 私が使用しているAPIのトークンは比較的短命(2時間)であり、アプリの使用中にユーザーがログインしたままになるように、システムに頭を悩ませようとしています。
それについて何か意見はありますか?

ユーザーのnext.jsを介してデータを渡さないことで、ページ遷移ごとにリクエストを保存することもできます。 これを行うには、server.jsのCookieからトークンを読み取り、ユーザーをフェッチして、それをnextのリクエストハンドラーに渡そうとします。 ドキュメントでは、小道具から取得し、window.USERのようにJSONで保存します。 次に、その場で、クライアントの土地にいるときにウィンドウからそれを読み取るだけです。 最後に、403コードを受信するとすぐにCookieを消去し、ページをリロードする応答インターセプターを備えたaxiosを使用する必要があります

@pbrandone繰り返しますが、最も単純で予測可能な解決策は、すべてのリクエストでトークンを送信し、レスポンスのヘッダー/本文で新しく更新されたトークンを受信することです。 クライアントは、要求/応答サイクルごとに既知の値を更新し、古くならず、誤用されない使い捨てトークンを効果的に付与します。

通常、このアプローチでは、 /token/refreshはアプリケーションの最初の「ウェイクアップ」( <App/> componentWillMountフックを考えてください)にのみ使用され、最後に保存されたかどうかを確認しますトークンは引き続き有効で使用可能です。

更新トークンを処理する必要はありませんでしたが、axiosインターセプターで処理しようとすると思います。 それについてもっと考える必要がありますが、理論的には、不正なリクエストをインターセプトし、更新トークンを使用して新しいトークンを取得し、新しいトークンでCookieを設定し、新しいトークンで最初のリクエストを再度再生します。 Axiosインターセプターは、このようなものを抽象化して製品コードから見えないようにすることができるため、非常に強力です。 要求と応答のインターセプターを作成したり、ヘアリーになる可能性のあるある種のステートフルな進行中のオブジェクト/マップを保持したりする必要がある場合があります。 うまくいけば、それが役立つ

またはルークが言ったことをしなさい。 はるかに簡単です。

更新トークンを実行する場合は、カスタムサーバーセットアップを介してCookieをインターセプトする必要があります(Cookieを使用している場合)。 私はエクスプレスを使用してこれを行いました。 それ以外の場合は、JWTトークンを使用してすべてのクライアント側で実行できます。 私はCookieを使用して作業を行っていたため、クライアント側でのナビゲーションリクエストの処理と、サーバー側でのページリクエストの処理という2つのユースケースがありました(誰かが手動でURLを入力したり、ページの更新を押したりした場合)。ただし、基本的には同じフローです。 1つはクライアント側で、もう1つはサーバー側であるため、実行方法が異なります。 Expressを使用していたので、サーバー側では、Cookieを処理し、その中のJWTをデコードして、有効期限を確認するミドルウェアを作成しました。 有効期限が切れている場合は、新しいトークンを取得するように要求し、デコードされたユーザーをクライアントのreduxに渡し続けます。 クライアントには、クライアントのどこかに移動するたびに、常にユーザーをチェックする安全なリンク用のHOCラッパーがあります。 HOCはあなたのCookieまたはJWT(私の場合は私のJWTはCookie内にあります)を取得し、それがまだすぐに有効かどうかを確認します。 有効でない場合は、更新されたJWT / Cookieを取得して続行しようとします。それ以外の場合は、ログアウトします。 はい、より複雑ですが、より安全でもあります。 お役に立てば幸いです。 興味があれば、遠慮なく質問してください。すべてを理解するのに少し時間がかかりました。 私は個人的にGithubやFBなどでログインしている人について疑問に思っています-おそらく多くの場合は大丈夫ですが、場合によっては専門家ではありません。 銀行、ヘルスケア、支払う請求書などはまだ見ていません。FBアカウントでログインしてください。 しかし、時間の問題かもしれません;)

アクセストークンの更新については、
これが適切な方法かどうかはわかりませんが、アクセストークンの有効期間は非常に短いです(1分程度)。 クライアント側のトークンの有効期限の問題に対処するために、私はこのアプローチを採用しました。
ページが読み込まれるたびに、トークンの有効期限が切れているかどうかがチェックされ、有効期限が切れている場合は更新されます。 ただし、それでも有効な場合は、有効期限までの時間をチェックするメソッドを呼び出し、有効期限が切れるとアクセストークンを更新するタイムアウトを設定します。 そして、訪問者がサイトにいる限り、このプロセスを繰り返します。

callRefreshAuthenticationLater(){
    clearTimeout(this.accessTokenRefreshmentTimeout)
    this.accessTokenRefreshmentTimeout = setTimeout(() => {
      this.refreshAuthentication()
    }, this.authService.howMuchUntilExpiration(this.authService.getToken('access_token')))
  }

これにより、有効期限が切れるまでミリ秒が返されます。

howMuchUntilExpiration(token){
    return normalizeTimestamp(jwtDecode(token).exp) - Date.now()
  }

このアプローチへのフィードバックは大歓迎です

@ kunokdev-それは良いスタートだと思います。 残り時間を計算する必要のある同様の関数を、期限切れかどうかに応じてブール値を返す関数に移動しました。これにより、コードが少し読みやすくシンプルになり、タイマーのリセットについて心配する必要がなくなりました。 次に、認証を必要とするあらゆる種類のリクエストで、ユーザーの有効期限が切れているかどうかを確認します。 カウントダウンタイマーなど、クライアントやデバッグに表示されるものがあれば、あなたの関数は理想的です。 それは私の2セントです👍

auth / loginの例は、可能な限り最も基本的な例ではありませんか? つまり、メモリストアであり、JWTや奇妙なトークンはありません。 通常、誰かが「ログイン」していると考えるとき、それは彼らがクッキー/アクティブセッションを持っていることを意味します。

ログインHOCが動作するクライアントとサーバー側があります。 JWTとバックエンド(ノード、djangoなど)を使用します。

それをチェックしてください、そして、どんなフィードバックも高く評価されます

https://github.com/hugotox/AppStarter

ここに関連するコードhttps://github.com/hugotox/AppStarter/blob/master/src/components/auth/login-required.js

@hugotox認証データを保存するためにReduxストアを使用するというアイデアは好きですが、 store.dispatchからgetInitialProps store.dispatchを数回呼び出すと、認証プロセスがあっても装飾されたコンポーネントがレンダリングされるときに、望ましくない副作用に備えることができますまだ終わっていません。 コードから使用例を見てみましょう。

export default withRedux(initStore, mapStateToProps)(
   loginRequired([PUBLIC])(MyPage)
)

getInitialPropsでは、 verificationOk verifyToken前にgetInitialPropsを呼び出すため、 MyPage.mapStateToPropsは2回呼び出され(store.auth.userをリッスンする場合)、最初はstore.auth.userは、ログインユーザーが必要なページでもnullになります。

昨日、独自のNext.jsを利用したスターターキットの最初のWIPバージョンもリリースしましたが、Docker、Flow、fast-reduxから始めました: https

異なるドメインで実行できるAPIサーバーとWebアプリ専用のDockerイメージを使用しているので、実際のユーザーにログインできるだけでなく、モバイルクライアント用にOAuthベアラートークンを発行できる実用的なソリューションを探しています。

@spencersmb素晴らしい歓声! これは、私が行っていた方法とほぼ同じです。 初めてアクセスしたとき(ログインしたことがない)のURLのサーバー側レンダリングに関して、Cookieがないことを確認し、たとえばpages / login.jsタイプのページにリダイレクトするだけですか?

@ james-ffそれを投稿してくれてありがとう、たとえそれが虚空に怒鳴りつけているように感じても。

このスレッドで何度か言われていますが、 localStorageを使用するJWTまたはJavaScriptでアクセス可能なCookieにセッショントークンを保存するべきではないことを誰もがまだ無視しているようで、安全性の低い方法でセッションと認証を再発明しようとしているようです(そしてそれはクライアント側のJSを必要とします)。 🙃🤦🏻‍♂️

この投稿の著者は何が問題になっているのかについて素晴らしい記事を書きましたが、残念ながら状況は改善されていないようです。

残念ながら、人々が読むのをやめる前に記事の長さの上限を見つけたようです-RedditとHacker Newsのコメント投稿者の多くは、同じ「解決策」を何度も何度も提案し続けました。記事自体に。

ただし、元の記事フォローアップ図はどちらも非常に優れています。

@iaincollins JWTとセッションレスアプリ/認証には利点があり、多くの人々/企業(Googleを含む)はまだそれらを使用したいと考えています。 JWTに対するケースを読んだ後でも、2つの公式のnext-authの例/ライブラリが必要だと思います。1つはセッション(next-authなど)を使用し、もう1つはJWTを使用するか、どちらかを使用できるようにするだけです。 長所、短所、および警告は、公式のNext.jsチュートリアルページおよび/またはモジュールドキュメントのどこかでそれぞれについて明確に説明する必要があります。 誰かがより良いボイラープレート/ライブラリを発明するまで、私はおそらくnextjs-starterとnext-authを使い続けるでしょう。なぜなら、それらは私が見つけた中で最高だからです。

私はこれを何気なく監視しているだけですが、ユニバーサルJS認証での私の経験は、JWTをHttpOnly Cookieに保存することです。 アプリのサーバー側を使用してCookieを保存するオプションがある場合、 localStorageを使用する理由は実際にはありません。 ブラウザでクロスオリジンAPI呼び出しのためにJWTにアクセスする必要がある場合は、 __INITIAL_STATE__タイプのシナリオでJWTを渡すことができます(XSSの脆弱性に注意してください。ただし、少なくとも「保存」しているわけではありません)。クライアント側)。 同一生成元のアクセスでは、クッキーは前後に渡されます(使用していると仮定するとwithCredentials axiosため、またはcredentials: 'include'すべてのJSでJWTを置く必要性を否定する、フェッチのため) 。 アプリのサーバー側でプロキシを使用して、 HttpOnly CookieからJWTを取得し、クロスオリジンAPI呼び出しを行うこともできます。 そのシナリオでも、プリフライトコールを無効にします。 それぞれに、しかし私は個人的に、localStorageがユニバーサルアプリに必要であるとは思いません。

@bjuncはい、JWTを保存する場所に関するすべてのオプション(localStorageとHttpOnly cookieとRedux、または何を持っているか)のうち、私は間違っているかもしれませんが、答えは基本的に常にHttpOnlycookieである必要があると思います。 これは、多くのブログやフォーラムで何度も述べられているようです。 (更新トークンについてはよくわかりません。おそらく、HttpOnly Cookieにも保存する必要がありますか?)JWTを保存する場所は、JWTのその他の長所/短所とは別に解決された問題である必要があると思います。

nextjs-starterとnext-authを採用し始める前に、私のプロジェクトであなたが言ったことを多かれ少なかれ正確にやろうとしました。 しばらく経ちましたが、正しく覚えていれば、認証対象のExpress APIサーバー(express-sessionを使用していた)がセッションを正しく初期化/フェッチしていなかったことが問題だったと思います。 セッションが複数回初期化されるという奇妙な動作が発生します。 私がそれを修正することができれば、私はあなたが説明したことを多かれ少なかれやり直すつもりです。 セッションは、トークンを無効にする方法など、JWTが提起する他の多くの懸念を排除するため、nextjs-starterとnext-authも引き続き使用します。

繰り返しになりますが、公式の例(または複数の例)が役立ちます。 キーワード:公式。Next.jsの作成者がすべての可能性を検討し、最良のアイデアと実践を取り入れたことを意味します。 理想的には、promiseやasync / awaitなどの最新のES6 / ES7 / ES8機能を使用します。

@ kelleg1あなたの問題はCookie作成の詳細に関連しているようです。 たとえば、異なる設定( HttpOnly 、ドメイン、パス、有効期限など)を使用して、同じ名前の複数のCookieを誤って作成する可能性があります。 あなたが説明しているような奇妙な副作用を引き起こす可能性があります。 これをデバッグする1つの方法は、開発ツールの[アプリケーション]-> [Cookie]を使用することです。 同じ名前のCookieがたくさん表示されている場合は、正しい方向を示している可能性があります。

とにかく、私はコアチームに所属していないので、「公式」の貢献を手伝うことはできません(実際、Next.jsではなくNuxt.jsを使用しています)が、原則は同じです。 私はこれを行うためのいくつかの異なる方法を試しました(JWT、Cookie、CSFR、WebSocket CSWSH、localStorageなどの長所/短所を比較検討します)。 最終的に、Next / Nuxtの普遍的な性質は、 HttpOnly JWTCookieの使用に適しているという結論に達しました。 他の人が別の結論に達するかもしれませんが、私は個人的に「ああ、JWTを使用しないでください。JWTがあなたに癌を与えるという記事を読んでいませんか!?」という陣営にはいません。

@iaincollinsはこれを再び

クッキー! :NS
次のようなものを使用します。

// auth.js
async signIn(res, info) {
    const { email, password } = info;
    const result = await this.service.signIn(email, password);
    if (!result) {
      res.status(HttpStatus.BAD_REQUEST).json({ success: false, message: 'Wrong email and/or password' });
      return;
    }
  const payload = {
    scope: 'appUser',
    userId: user.email,
    language: user.language,
    iat: moment().unix(),
    exp: moment().add(7, 'days').unix(),
    type: user.type,
    status: user.status
  };
    const token = jwt.sign(payload, ...);

    res.cookie('token', token, { domain: 'yourdomain.com', path: '/', secure: true, httpOnly: true, maxAge: 24 * 60 * 60 * 1000 * 7, signed: true });

    res.status(HttpStatus.OK).json({});
  }

// pages/index.js

class Index extends PureComponent {
  render() {
    return (
      <Layout title="home">
        <Home />
      </Layout>
    );
  }
}

Index.getInitialProps = async ({ req, res }) => {
  const auth = req ? getServerSideToken(req) : getClientSideToken();
  return { auth };
}
export default Index;

// utils/auth.js
const decode = ({ token }) => {
  const decoded = jwt.decode(token);
  const { userId, type = 'anonymous', status, language = 'en' } = decoded || {};
  return { user: { email: userId, type, status, language } };
};

export const getServerSideToken = (req) => {
  const { signedCookies } = req;

  if (!signedCookies) {
    return {};
  }
  try {
    return decode(signedCookies);
  } catch (parseError) {
    console.error(parseError, signedCookies);
    return {};
  }
};

export const getClientSideToken = () => {
  if (typeof window !== 'undefined') {
    const user = window.__USER__ || {};
    return { user };
  }
  return { user: {} };
};

// pages/_document.js
export default class extends Document {
  static async getInitialProps(ctx) {
    const props = await Document.getInitialProps(ctx);
    const info = getServerSideToken(ctx.req);
    return { ...props, ...info };
  }

  render() {
    const { user = {} } = this.props;
    const json = JSON.stringify(user);
    return (
      <html lang="en">
        <Head>
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <meta charSet="utf-8" />
          <link href="//fonts.googleapis.com/css?family=Kadwa:400,700|Work+Sans:100,300,600" rel="stylesheet" />
          <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.14/semantic.min.css" />
          <link rel="stylesheet" href="/static/site.css" />
        </Head>
        <body>
          <Main />
          <script
            dangerouslySetInnerHTML={{ __html: `__USER__ = ${json};` }}
          />
          <NextScript />
        </body>
      </html>
    );
  }
}

// somewhere.js
import axios from 'axios';
axios.defaults.withCredentials = true;
axios.post(`${apiBaseUrl}/some/path`, data)...

// somemiddleware.js
      const { signedCookies = {} } = req;
      const { token = '' } = signedCookies;
      if (token) {
        try {
          const info = jwt.verify(token, ...);
          req.user = await this.getUser(info.userId);
          if (req.user) {
            next();
            return;
          }
        } catch (err) {
          console.error({ permissionError: err });
          return res.status(500).json({...});
        }
      }
      return res.status(403).json({...});

クライアント側のJavaScriptはトークンを認識せず、CookieはhttpOnly、安全、署名され、 axiosまたはその他によって自動的に送信されるため、少し厄介ですがかなり安全です...

みなさん、こんにちは。Cookieとreduxを使用して認証例を作成しました。 こちらをご覧くださいhttps://github.com/zeit/next.js/pull/4011

待って、この問題はどこで終わったのですか? 公式リポジトリでExpress認証の例を見つけることはできませんでした。

Cookieやセッションについて多くの話がありますが、APIにアクセスする必要がある場合、ネイティブモバイルアプリではどのように機能しますか?

@jackjwilliamsモバイルアプリのHTTPライブラリもCookieをサポートするべきではありませんか?
https://stackoverflow.com/questions/1660927/iphone-make-post-request-handle-cookie
https://stackoverflow.com/questions/678630/how-do-i-make-an-http-request-using-cookies-on-android

それは可能ですが、それがJWTの目的です:p

このスレッド全体を詳細に読んだところですが、調査結果を要約する必要があると感じています。

確かな認証モジュールが除外された2つの実行可能なスタータープロジェクトがあるようです。

@iaincollins@nmaroによる素晴らしい作品です!

ありがとう@curran :)

このプルリクエストhttps://github.com/iaincollins/nextjs-starter/pull/86で、nextjs-starterの無関係な側面をガットするために行ったすべてのコード変更を文書化しました

これは、Next.jsリポジトリの堅実な最低限の認証例に近づいている可能性があります。

最近、Office 365でOAuthを実装する必要があったので、ここでまとめた非常に簡単な例を共有したいと思いここにある保護されたルートのスレッドを利用し

クライアント側とサーバー側で機能する単純なJWTトークン化認証に関心のある人のために、Spectrumチャットで助けを得て、それを皆さんと共有したいと思いました。 フィードバックはいつでも歓迎します。

https://github.com/bgold0/nextjs-auth-skeleton

こんにちは、みんな!
これは、私が数か月前に作成したnext.jsを使用した認証の別の例です。おそらく、誰かがそれを役立つと思うでしょう。

https://github.com/alan2207/nextjs-jwt-authentication

Ooth 2.0は、新しくより優れたドキュメントリリースされました

Oothは、node.js用に構築されたユーザーID管理システムです(next.jsを念頭に置いて)。

現在サポートされている戦略:

  • プライマリ:ユーザー名/パスワード(メールの確認、pwの忘れなどを含む)、ゲスト、Facebook、Google
  • セカンダリ:Cookieベースのセッション、JWT

next.js(ソースコード)とすべてをまとめたこのライブの例を確認してください。

ここ(およびexamplesフォルダー)の認証サンプルの多くは、 getInitialPropsからユーザーsession / token / etcを返します。 私の知る限り、ページがサーバー側でレンダリングされると、これはユーザーセッション情報がHTMLページ応答の一部として( NEXT_DATA一部として)ブラウザーに送信されることを意味します。

getInitialPropsをサーバー側で実行すると、このパターンに2つのセキュリティ問題が発生します。
1)ユーザーセッションは、ネットワークを介してサーバーからブラウザに送信されます。 どのような要求が使用している場合はhttp://及びませんhttps://など、ユーザーのトークンをプレーンテキストでネットワーク上で公開されるだろう。

2)ユーザーセッションは、HTMLページの一部として( NEXT_DATAスクリプトタグで)サーバーからブラウザーに返されます。 ユーザーのトークンなどをHTMLページに直接配置することは危険であるように思われます。特に、ページが解析され、ブラウザーによってレンダリングされ、他のサードパーティのスクリプトが実行されている場合はなおさらです。

これらの問題はすでに対処されていますか? これらの脅威に対する緩和策はありますか?

だから私はクッキーを使います。 ここで私の例を参照してくださいhttps://github.com/hugotox/nextjs-starter/blob/master/pages/_app.js

ついに! ここでは、次のコンテナを使用して完全にドッキングされたnext.js認証の例を見つけることができます。

  • next.js
  • authマイクロサービス(ooth)
  • api(graphql)
  • セッションストレージ(redis)
  • 小さなリバースプロキシ

すべてがdocker-composeでまとめられています。

JWTに関するクイックノート。 JWTには、ステートレスであり、モバイルに適しており、あるドメインから別のドメインにクレデンシャルを渡す必要がある場合に適しているという利点があります。 主な欠点は、ブラウザがXSSにさらされることです。 この例では、純粋なCookieセッションベースのソリューションを選択しました。 リバースプロキシ(すべてのマイクロサービスは同じドメインで実行されます)と共有セッションストレージのおかげで、マイクロサービスに分割することができました。

https://github.com/nmaro/staart/tree/master/examples/staart
ライブの例は、いつものように、 https

JWTを使用しても、本質的にXSSに「さらされる」わけではないので、明確にするのが賢明だと思います。 むしろ、サイトにXSSの脆弱性がある場合(JWT自体が原因ではない)、JWTが(他のスクリプトでアクセス可能な情報とともに)侵害される可能性があります。 一方、 httpOnly Cookieにはアクセスできません。 httpOnly cookieの値としてJWTを使用できることを忘れないでください。

Cookieのみのソリューションは、同じドメインの通信に適していますが、ヘッドレスAPI(たとえば、 example.comapi.example.com呼び出す)を使用している場合、ブラウザをプロキシする必要がない限り、これは実際にはソリューションではありません。以下からの要求example.comapi.example.comにあなたのAPI呼び出しを行うことにより、 example.comと(長所/短所の独自のセットが付属しています)リクエストに追加クッキーとのそれらを転送します。

個人的には、JWTの短所は非常に誇張されており、一般的に実装されている多数の保護によって簡単に軽減できると感じています。 特に、有効期限が切れる前にトークンが侵害された場合に、 jtiクレーム(バージョン4 UUIDなど)を参照するトークンブラックリスト。

ねえ@bjuncはい明確にしてくれてありがとう。 正解です。JWT自体はXSSにさらされません。 あなたの他の観察に関して、私はそれらがそれぞれ彼らの落とし穴を持っていることを付け加えたいと思います。

httpOnlyCookieの値としてJWTを使用できることを忘れないでください。

はい、ドメイン間でクレデンシャルを転送するというJWTの利点の1つを取り除くことを追加したいと思います。

トークンブラックリスト

それと、更新トークンの他の一般的な方法は、実際にステートレスであるというJWTの他の利点を取り除きます。

これは状況についての私の理解です:

  • クロスロケーション認証が必要な場合はJWT <-を使用します
  • ブラウザではなく、XSSの問題がないクライアント(デスクトップやモバイルアプリなど)から認証する必要がある場合は、JWTを使用してください
  • それ以外の場合は、Cookieベースのセッションを使用します。JWTベースのソリューションは安全性が低い(XSS)か、実際にはステートレスではない(ブラックリスト)か、プロキシを使用してすべてを同じドメインに保持する必要があるためです。

Next.js認証/ユーザーアカウントに関する中程度の記事を書きました。
これは広範なチュートリアルであり、ほぼ2年間の余暇の開発と思考からの私のブレインダンプです(この問題に関する私の最初のコメントは2017年2月からです)。

https://medium.com/the-ideal-system/user-accounts-with-next-js-an-extensive-tutorial-6831cdaed16b

JWTと安全性の低下との相関関係を維持します。 JWTによってサイトの安全性が低下することはありません。 それ自体はXSSの脆弱性ではありません。 XSSエクスプロイトがある場合は、関係なく同じように問題が発生します。 httpOnly Cookieを使用しても、攻撃者はCookie値を読み取れない可能性がありますが、セッションCookieを自動的に渡すXHRリクエストのように、任意のコードを実行できるため、問題ではありません(基本的には次のように機能します)。 CSRF攻撃)。 APIがクロスドメインであり、ブラウザーからサーバーへのリクエストを行っている場合、JWTはとにかくコードのどこかにあります(初期状態であれ、localStorageであれ)。 Axiosを使用している場合は、グローバルなデフォルトを設定している可能性があります。攻撃者はAxiosリクエストを行うだけで、認証について心配する必要はありません。

また、CSRFについても話さずにXSSについて実際に話すことはできません。 ここで、認証Cookieは特に対象とされています。 リバースプロキシ設定を使用している場合でも、CSRF攻撃により、攻撃者はAPIに対して認証されたリクエストを実行できます。

ところで、JWTをCookieに入れたからといって(たとえば、ユーザーがログインしているかどうかを知る)、クロスドメインサーバー間でCookie値(JWTなど)を使用できなくなるわけではありません。ページ読み込み時のAPIサーバーアクセス(これはリバースプロキシシナリオでも機能します)。 また、ブラウザからAPIサーバーへのリクエストについても、初期状態でJWTを渡すことを妨げられたりすることはありません。 それらは相互に排他的ではありません。

余談ですが、「ステートレス」JWTのアイデアは、ほとんどのユースケースのアプリケーションで過大評価され、制限されていることがわかります。 例えば:

  • リソースベース/動的権限(例:「 can edit Post 」だけでなく「 can edit Post:1634 」)。
  • ユーザーのアカウントがブロック/削除された場合はどうなりますか?
  • 毎月のサブスクリプションを支払っていません。 機能を調整するのはどれですか?
  • トークンをブラックリストに登録しましたか(上記のとおり)?

これらすべてをJWTに焼き付けているわけではありません。つまり、ドメインレイヤー(つまりデータベース)を調べて調べる必要があります。 リソースをロードしたばかりなので、アプリの他の部分がリソースにアクセスできる場所にリソースを配置すると、状態がわかります。 主題について知る必要があるすべてがトークンに焼き付けられると考えるのは本当にばかげていると思います。 同時にそれをほとんど匿名で軽量に保ちます。 あまり逸脱することなく、サービス間通信での「ステートレス」リクエストについての議論がありますが、それでも私は実用的ではないと思います(少なくとも、主題について知る必要があることをJWTに焼き付けるという概念に関係しているため)。 。

その間に利用可能な他の認証戦略(太字の新機能):

  • ローカル(ユーザー名/メール/パスワード)
  • フェイスブック
  • グーグル
  • ゲスト
  • Patreon
  • ツイッター
  • Authy(Twilio)-SMS経由でパスワードなし

あなたが書いた@jaredpalmer
phpと同様に、Nextのアトミックユニットはページです。 最も優れた機能の1つは、要求された場合にのみ各ページを遅延ロードすることです。 クライアント側のみの認証で、サーバーレンダリングでは、その保護されたページのjsは実際にはブラウザによってダウンロードされます。 将来、Nextがサーバーワークフローを追加するときに、サーバーでのレンダリングとリダイレクトをブロックして、これを完全に防ぐことができるようになることを願っています。 これにはCookie、セッション、およびAFAIKセッションストアが必要ですが、これはこれらのようなハイブリッドアプリを実行するためのコストにすぎません。

2年後です。 保護されたページのjsの読み込みを防ぐサーバーワークフローはありますか?
@timneutkensは、保護されたコンテンツを他のゾーンに配置している可能性がありますか?
保護されたコンテンツへのアクセスを完全に防ぐにはどうすればよいですか?

@lishineページのgetInitialPropsServerResponseがあります-特権のない人を簡単にリダイレクトできます。

reduxを使用した認証の例はありますか?

reduxを使用した認証の例はありますか?

reduxを使用しているこの例を試して、それがあなたのために働くかどうかをチェックすることができます...
このトピックのどこかにありますが、見つからない場合は、次のようになります。
https://github.com/alan2207/nextjs-jwt-authentication

仮想DOMはLOGOUT-LOGINアクションの後に古い結果を使用するため、サーバー側API呼び出しの結果getInitialPropsを使用する場合、これはより複雑な問題だと思います。 私は解決策を考えています

_編集済み_
これがredux-observableでの私の答えです

|サイド|認証| TODO |
| --- | --- | --- |
|サーバー| true |初期データを取得します(リクエストCookieプロキシを使用)。|
|サーバー| false |ログインページを表示し、ログイン後にデータを取得します。|
|クライアント| true |初期データを取得します。|
|クライアント| false |ログインページを表示し、ログイン後にデータをフェッチします。 (これは、ページ間移動でセッションが期限切れになった場合にのみ発生します)|

  static async getInitialProps({ store, query: { rowsPerPage, pageIndex }, req, auth }) {
    store.dispatch(TemporaryStoryActions.initPageState());

    const isAuthenticated = () => req ? req.isAuthenticated()
      : store.getState().auth.isAuthenticated;

    if (isAuthenticated()) {
      // fetch initial data
      const TemporaryStoryApiProxy = withCookieProxy(req, TemporaryStoryApi);
      await TemporaryStoryApiProxy.fetchTemporaryStories({
        rowsPerPage: rowsPerPage || 15,
        pageIndex: pageIndex || 0,                                                                                                                                  }).then(json => {
        store.dispatch(TemporaryStoryActions.loadTemporaryStories(
          json.rowsPerPage, json.pageIndex, json.count, json.rows));
      }).catch(error => {
        if (error.response && error.response.status === 403) {
          store.dispatch(AuthActions.initState(false, null));
          return;
        }
        throw error;
      });
    }

    if (!isAuthenticated()) {
      // => if client side fetch failed with 403, isAuthenticated() turns off to false
      // register logined action for client side login succeeded
      const reloadAction = TemporaryStoryActions.fetchTemporaryStories({
        rowsPerPage: rowsPerPage || 15,
        pageIndex: pageIndex || 0,
      });
      store.dispatch(AuthActions.addLoginedAction(reloadAction));
    }

    return {
      ...store.getState(),
    }                                                                                                                                                           }                                                                                             }
export const withLogin = Page => class SecurePage extends React.Component {
  static async getInitialProps (ctx) {
    if (ctx.req && ctx.store) {
      // server side
      const isAuthenticated = ctx.req.isAuthenticated();
      const { user } = ctx.req;
      ctx.store.dispatch(AuthActions.initState(isAuthenticated, user));
    }
    return Page.getInitialProps && await Page.getInitialProps(ctx)
  }

  render () {
    const { auth } = this.props;
    return auth.isAuthenticated ? <Page {...this.props} /> : <LoginPage />
  }                                                                                                                                                           }
// when [front-end server] => [api server]
// on Server Side Rendering,
// needs to proxy Cookies which sent to Next.js page request
export const withCookieProxy = (req, targetApi) => {
  if (!req) {
    return targetApi;
  }
  targetApi.client.interceptors.request.use(config => {
    const cookieString = Object.keys(req.cookies).map(key => `${key}=${req.cookies[key]}`).join('; ');
    const headers = {
      ...(config.headers || {}),
      Cookie: cookieString,
    };
    return {
      ...config,
      headers: headers,
    };
  }, error => {
    return Promise.reject(error);
  });
  return targetApi;
};
const loginEpic = (action$, state$) => action$.pipe(
  ofType(AuthActionTypes.login),
  mergeMap(action => {
    const email = action.payload.email;
    const password = action.payload.password;
    return from(AuthApi.login(email, password))
      .mergeMap(json => {
        const user = json.user;
        const loginedActions = state$.value.auth.loginedActions;
        const successActions = [
          AuthActions.removeAllLoginedActions(),
          ...loginedActions,
          AuthActions.loginSuccess(user.id, user.name, user.last_login_date),
        ];
        return from(successActions);
      }).pipe(catchError(error => {
        return of$(AuthActions.loginFail(error));
      }));
  }));

単純なことをすると、次のように複雑になります。

export const withAuthSync = WrappedComponent => class extends Component {
  componentDidMount() {
    window.addEventListener('storage', this.syncLogout);
  }

  componentWillUnmount() {
    window.removeEventListener('storage', this.syncLogout);
    window.localStorage.removeItem('logout');
  }

    syncLogout = (event) => {
      if (event.key === 'logout') {
        console.log('logged out from storage!');
        window.location.reload();
      }
    };

    render() {
      return <WrappedComponent {...this.props} />;
    }
};

この例は、Next.js8の一部としてマージされました。
https://github.com/zeit/next.js/tree/canary/examples/with-cookie-auth

@timneutkensリンクをありがとう。

https://github.com/zeit/next.js/blob/canary/examples/with-cookie-auth/www/utils/auth.js#L26 -L34 ...を見てauth()が呼び出された後に確認しますか?

Cookieなしで例をテストすると、 Profile.getInitialProps()が呼び出されますが、「初期小道具」をさらに取得しようとする前にリダイレクトが発生すると思いました...

ここで、サーバー側の事前レンダリングとapolloを使用した認証を使用した例を作成しました。

https://github.com/Horizo​​nShadow/apollo-next-now-test

OWASPセキュリティガイドラインでは、JWTトークンをローカルストレージに保存しないことを推奨しています。つまり、「単一のクロスサイトスクリプティングを使用してこれらのオブジェクトのすべてのデータを盗むことができるため、機密情報をローカルストレージに保存しないことをお勧めします」。

Auth0:トークンTom Abbott:JWTの保存場所–CookieとHTML5Webストレージ

これは、Nuxt.js + Express.jsプロキシサーバー+ Djangoバックエンドの例です。 Expressサーバーが認証リクエストを実際のバックエンドにプロキシするために使用され、Cookieに保存されているJWTトークンを使用するときにCSRF保護を処理している場合(トークンの長さ/ JWTトークンに保存できる情報の量に制限があります): https:/ /github.com/danjac/nuxt-python-secure-example

@ timneutkensCookie🍪からSSRカスタムreduxミドルウェアにトークンを送信する方法に関するドキュメントが必要です。 _app.js内にCookieを取得しています。 しかし、どのようにそれをcustomApimiddlewareに渡す必要がありますか。 フェッチリクエストを書いたところ。 ありがとう

Next.js認証/ユーザーアカウントに関する中程度の記事を書きました。
これは広範なチュートリアルであり、ほぼ2年間の余暇の開発と思考からの私のブレインダンプです(この問題に関する私の最初のコメントは2017年2月からです)。

https://medium.com/the-ideal-system/user-accounts-with-next-js-an-extensive-tutorial-6831cdaed16b

これは、nextj.jsアプリで認証を処理するための最良のチュートリアルの1つだと思います。 トークンをlocalStorage(XSS)に保存したり、トークンをCookieに保存したり(CSRFを処理せずに)、ブラウザーからCookieにトークンを保存したり(XSSとCSRFの両方が脆弱)などのことを見てきました。

リバースプロキシを使用し、異なるサービス間でセッション情報を共有するソリューションが本当に気に入っています。 next.jsアプリ用のカスタムサーバーを作成したくないのですが、セッションの処理とcsrfの防止(およびリバースプロキシの追加)の両方を行う最も簡単な方法だと思います。 モノリスプロジェクトを作成することさえあるかもしれません(アプリのレンダリングとデータベース操作の処理の両方のため)。

一部の人々(ZEITを含む)はAPIをステートレスに保ち、next.jsアプリにセッションを処理させるのを見てきました。 トークンをAPIに渡します。 しかし、セッションに参加することで、物事が少し厳しくなり、複雑さが軽減されるだけです。

next.jsの完全な認証例があると本当に良いでしょう。 外部APIの認証、next.jsアプリでのセッションの維持、サービス間でのセッションの共有、サービスへのトークンの受け渡し、有効期限が切れた場合のトークンの更新などが含まれます。 (多くの人がJWTについて多くのことを書き、チュートリアルで使用していますが、ほとんどの場合、JWTの有効期限が切れたり、更新されたりすることはありません。)

とにかく、あなたはこの主題に関する最も完全なチュートリアルの1つを書きました。 ほんとありがと!

より完全で明確な例とドキュメントがあることを本当に望んでいます。

next.jsの完全な認証例があると本当に良いでしょう。 外部APIの認証、next.jsアプリでのセッションの維持、サービス間でのセッションの共有、サービスへのトークンの受け渡し、有効期限が切れた場合のトークンの更新などが含まれます。 (多くの人がJWTについて多くのことを書き、チュートリアルで使用していますが、ほとんどの場合、JWTの有効期限が切れたり、更新されたりすることはありません。)

私も、どちらのアプローチを選ぶべきか迷っています。
記事へのリンクありがとうございます。
現在、どの実装に落ち着きましたか?
次のv9.3 +の包括的な認証例を見つけましたか?

Auth0の新しいCookieベースのアプローチをチェックする価値があります
(もちろん、これは特定のIDプロバイダー向けですが、アプローチを確認すると役立つ場合があります)
https://github.com/auth0/nextjs-auth0

  • nextjsのAPIルートを介して(1つの動的ルートを介しても)APIリクエストを「プロキシ」できるのは本当に素晴らしいことです。
  • そうすれば、アクセストークンなどをクライアント側に公開する必要はありません(nextjs apiルートはサーバー側のみを実行するため)。サーバー側は、auth0ライブラリと秘密のCookieを介してアクセストークンなどを取得できます。
  • クライアント側のコードはnextjsAPIルートを呼び出し、APIルートは実際のAPIリクエストを実行します

このアプローチはReadMeでは「実験的」であると彼らが言っていることを覚えておいてください

Auth0の新しいCookieベースのアプローチをチェックする価値があります
(もちろん、これは特定のIDプロバイダー向けですが、アプローチを確認すると役立つ場合があります)
https://github.com/auth0/nextjs-auth0

  • nextjsのAPIルートを介して(1つの動的ルートを介しても)APIリクエストを「プロキシ」できるのは本当に素晴らしいことです。
  • そうすれば、アクセストークンなどをクライアント側に公開する必要はありません(nextjs apiルートはサーバー側のみを実行するため)。サーバー側は、auth0ライブラリと秘密のCookieを介してアクセストークンなどを取得できます。
  • クライアント側のコードはnextjsAPIルートを呼び出し、APIルートは実際のAPIリクエストを実行します

このアプローチはReadMeでは「実験的」であると彼らが言っていることを覚えておいてください

この記事は非常に役立ち、さまざまなアーキテクチャをカバーしています。
https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/

APIルートをプロキシとして使用し、APIルートを介してログイン/ログアウトし、APIからトークンを取得し、それをHttpOnlyCookieとして設定することは確かなアプローチだと思います。
1つの懸念はCSRFかもしれませんが、 csrf npmパッケージを使用して簡単にソリューションを作成できます( csurfではありませんが、それでも機能する可能性があります)。

@ onderonur 、auth0の記事をありがとう。
つまり、現在、next.jsを使用した純粋なjwtでの実装の信頼できる、または少なくとも最小限の例がありますか?
Cookieを使用して高度なレイヤーを作成して設定したくありません。 csrアプリケーションでは、トークンをlocalstorageに保存し、リクエストと一緒に送信しました。

@ onderonur 、auth0の記事をありがとう。
つまり、現在、next.jsを使用した純粋なjwtでの実装の信頼できる、または少なくとも最小限の例がありますか?
Cookieを使用して高度なレイヤーを作成して設定したくありません。 csrアプリケーションでは、トークンをlocalstorageに保存し、リクエストと一緒に送信しました。

私は自分のリポジトリの1つにこの方法を使用しましたが、まだドラフト中であるため、必ず自分でテストしてください:)
https://github.com/onderonur/post-gallery
実際、「クッキーレイヤー」は高度なものではありません。 /api/login APIルートを介してAPIのログインエンドポイントを呼び出すだけで、リクエストが成功した場合は、トークンをhttpOnly Cookieに設定します。
まったく同じ実装については、私のリポジトリを確認できます。

もう1つのオプションは、(ローカルストレージにトークンを設定するのとほぼ同じフローが必要な場合)、 js-cookie npmパッケージを使用し、クライアント側のリクエストでログインエンドポイントを呼び出し、返された場合に終了することです。トークン、クッキーに設定します。 また、(axiosインターセプターなどを介して)リクエストを行う場合は、Cookie値を読み取り、リクエストヘッダーとしてAPIに渡します。 私はこのアプローチを使用する多くの(そしていくつかの人気のある)アプリケーションを見てきました。 しかし、これは少し安全ではありません。 ブラウザでhttpOnly Cookieを設定できないためです。 したがって、JavaScriptはトークンCookieを読み取ることができます。 したがって、XSSの脆弱性があります。

これは古いスレッド(そして一般的には長期にわたるトピック)であることを理解してください。しかし、追加のリファレンスや例を探している人のために、最近NextAuth.jsv2での作業を取り上げました。 私はそれをプラグとしてではなく、オープンソースプロジェクトであり、多くの人々がそれを手伝ってくれましたが、使い方はとても簡単で、コードとアプローチは人々への参照として役立つかもしれません。

NextAuth v1などの一部のバックグラウンドでは、署名、プレフィックス、HTTPのみのCookieを使用し、クライアント側のトークンを使用する際の一般的なセキュリティ上の落とし穴を回避します。

NextAuth.js v2は、Apple、Google、Facebook、Twitter、GitHub、Auth0、Okta、Slack、Discord、およびその他のOAuthプロバイダー(1.xと2.xの両方をサポート)でのサインインをサポートしています。 MySQL、MariaDB、Postgres、MongoDBで使用することも、データベースをすべて使用しないこともできます(100%サーバーレスソリューションの場合はOAuthとJSON Webトークンのみ)。

使い方は非常に簡単です、ユニバーサル静的メソッドが呼び出されたsession()とフックが呼ばれる反応useSession()あなたがコンポーネントのクライアント側で使用することができます。

import { useSession } from 'next-auth/client'

export default () => {
  const [session, loading] = useSession()

  return <>
    {!loading && session && <p>Signed in as {session.user.name || session.user.email}.</p>}
    {!loading && !session && <p><a href="/api/auth/signin">Sign in here</a></p>}
  </>
}

Next.js 9.xおよびサーバーレス用に構築されており、ExpressやPassportJSのような依存関係はありません。 これには、 _app.js使用して、すべてのページに認証状態を自動的に追加できる認証プロバイダーが含まれています。 クライアント側とサーバー側の両方のレンダリングで機能します。

詳細については、 next-auth.js.orgを参照するか、NPMでnext-auth @betaを確認してください。

  • ホームページ: https
  • デモ: https
  • NPM: npm i next-auth@beta

それはまだ進行中の作業です-私たちはまだドキュメントとイベントモデルを磨き上げています-6月中旬のリリース予定日です。

これは古いスレッド(そして一般的には長期にわたるトピック)であることを理解してください。しかし、追加のリファレンスや例を探している人のために、最近NextAuth.jsv2での作業を取り上げました。 私はそれをプラグとしてではなく、オープンソースプロジェクトであり、多くの人々がそれを手伝ってくれましたが、使い方はとても簡単で、コードとアプローチは人々への参照として役立つかもしれません。

NextAuth v1などの一部のバックグラウンドでは、署名、プレフィックス、HTTPのみのCookieを使用し、クライアント側のトークンを使用する際の一般的なセキュリティ上の落とし穴を回避します。

NextAuth.js v2は、Apple、Google、Facebook、Twitter、GitHub、Auth0、Okta、Slack、Discord、およびその他のOAuthプロバイダー(1.xと2.xの両方をサポート)でのサインインをサポートしています。 MySQL、MariaDB、Postgres、MongoDBで使用することも、データベースをすべて使用しないこともできます(100%サーバーレスソリューションの場合はOAuthとJSON Webトークンのみ)。

使い方は非常に簡単です、ユニバーサル静的メソッドが呼び出されたsession()とフックが呼ばれる反応useSession()あなたがコンポーネントのクライアント側で使用することができます。

import { useSession } from 'next-auth/client'

export default () => {
  const [session, loading] = useSession()

  return <>
    {!loading && session && <p>Signed in as {session.user.name || session.user.email}.</p>}
    {!loading && !session && <p><a href="/api/auth/signin">Sign in here</a></p>}
  </>
}

Next.js 9.xおよびサーバーレス用に構築されており、ExpressやPassportJSのような依存関係はありません。 これには、 _app.js使用して、すべてのページに認証状態を自動的に追加できる認証プロバイダーが含まれています。 クライアント側とサーバー側の両方のレンダリングで機能します。

詳細については、 next-auth.js.orgを参照するか、NPMでnext-auth @betaを確認してください。

  • ホームページ: https
  • デモ: https
  • NPM: npm i next-auth@beta

それはまだ進行中の作業です-私たちはまだドキュメントとイベントモデルを磨き上げています-6月中旬のリリース予定日です。

これは素晴らしい仕事です!
これはクライアント側だけで使用できますか? たとえば、私はRails APIアプリを持っており、クライアント側に次のJSを使用しています。

このページは役に立ちましたか?
0 / 5 - 0 評価