Next.js: Ajouter un exemple de connexion / authentification

CrĂ©Ă© le 29 oct. 2016  Â·  208Commentaires  Â·  Source: vercel/next.js

Avec:

  • assistant d'authentification rĂ©utilisable sur toutes les pages
  • synchronisation de session entre les onglets
  • backend de messagerie simple sans mot de passe hĂ©bergĂ© sur now.sh

Je pense que cela sera extrĂȘmement utile pour beaucoup de nouveaux arrivants.

p0

Commentaire le plus utile

J'ai donc l'authentification qui fonctionne à merveille. Comme mentionné ailleurs, il s'agit uniquement du cÎté client, ce qui n'est finalement que la moitié de la bataille.

"Assez sécurisé"

Comme php, l'unitĂ© atomique de Next est la page. L'une des fonctionnalitĂ©s les plus intĂ©ressantes est qu'il charge paresseux chaque page uniquement lorsque cela est demandĂ©. Avec l'authentification cĂŽtĂ© client uniquement mais avec le rendu serveur, le js de cette page protĂ©gĂ©e est en fait tĂ©lĂ©chargĂ© par le navigateur. À l'avenir, lorsque Next ajoutera des workflows de serveur, vous pourrez, espĂ©rons-le, bloquer le rendu et la redirection sur le serveur pour empĂȘcher cela complĂštement. Cela nĂ©cessitera des cookies, des sessions et des magasins de sessions AFAIK, mais ce n'est que le coĂ»t de crĂ©ation d'applications hybrides comme celles-ci.

Exemple d'authentification

Supposons que vous ayez une API sĂ©curisĂ©e par JWT avec deux points de terminaison d'intĂ©rĂȘt : /token et /me . /token accepte les informations d'identification par e-mail/mot de passe et renvoie un JWT signĂ© ( id_token ) tandis que /me renvoie les informations de profil relatives Ă  l'utilisateur authentifiĂ© par JWT. J'ai adaptĂ© le AuthService.js suivant du verrou d'Auth0 (en supprimant l'Ă©metteur d'Ă©vĂ©nements, bien que ce ne soit pas la pire idĂ©e). Il extrait presque tout le traitement des jetons JWT afin qu'il puisse ĂȘtre utilisĂ© sur la page de connexion et Ă©galement dans un composant d'ordre supĂ©rieur (nous en parlerons plus tard).

// 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())
  }
}

Ensuite, il y a un HOC pour simplifier la protection des pages. Pour éviter un flash indésirable d'informations sensibles, la page affichera sur le serveur Loading... lors du premier rendu pendant que React démarre / lit le jeton à partir de localStorage. Cela signifie que les pages protégées ne seront

// 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) 

La page de connexion ne peut pas utiliser le HOC tel qu'il est actuellement, car la connexion doit ĂȘtre publique. Il crĂ©e donc directement une instance d'AuthService. Vous feriez Ă©galement quelque chose de similaire pour une page d'inscription.

// ./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

InspirĂ© par les styles de rĂ©action d'Airbnb, j'ai Ă©galement commencĂ© Ă  travailler sur une next-with-auth qui serait une fonction qui renvoie un HOC Ă  utiliser sur les pages. J'ai aussi jouĂ© avec la fusion de AuthService et ce HOC. Une solution pourrait ĂȘtre de faire en sorte que ce HOC accepte une fonction de niveau d'autorisation comme argument en plus du composant, comme redux connect. Quoi qu'il en soit, dans mon esprit, vous utiliseriez next-with-auth comme ceci :

// ./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,
})

Faire tout cela avec Redux semblait inutilement compliqué, mais en gros, vous pouvez suivre l'exemple du wiki, mais déplacer AuthService dans Actions (connexion et déconnexion) et avoir un User Reducer. Cependant, vous ne pouvez appeler ces actions que sur le client, car il n'y a pas de localStorage sur le serveur, vous devez donc vérifier cela dans vos actions. En fin de compte, le magasin redux est mis sur le window toute façon. Ainsi, vous pouvez simplement mettre en cache l'utilisateur sur window au lieu d'utiliser le contexte. Si vous ne voulez pas de redux, vous pouvez également essayer react-broadcast .

Enfin, en supposant que next/server soient expédiés selon #25. next-with-auth pourrait soustraire au développeur les éléments compliqués du stockage local par rapport aux cookies avec un middleware + un HOC. Il pourrait également gérer le rafraßchissement des jetons.

Tous les 208 commentaires

Suggestion : utilisez Redux et JWT pour réaliser l'exemple

Je travaille sur un exemple pour cela. J'ai actuellement des problĂšmes pour que componentWillReceiveProps se dĂ©clenche sur mon composant de haut niveau (oĂč je prĂ©vois de vĂ©rifier si l'utilisateur est authentifiĂ© et rediriger vers la page de connexion sinon)

J'ai donc l'authentification qui fonctionne à merveille. Comme mentionné ailleurs, il s'agit uniquement du cÎté client, ce qui n'est finalement que la moitié de la bataille.

"Assez sécurisé"

Comme php, l'unitĂ© atomique de Next est la page. L'une des fonctionnalitĂ©s les plus intĂ©ressantes est qu'il charge paresseux chaque page uniquement lorsque cela est demandĂ©. Avec l'authentification cĂŽtĂ© client uniquement mais avec le rendu serveur, le js de cette page protĂ©gĂ©e est en fait tĂ©lĂ©chargĂ© par le navigateur. À l'avenir, lorsque Next ajoutera des workflows de serveur, vous pourrez, espĂ©rons-le, bloquer le rendu et la redirection sur le serveur pour empĂȘcher cela complĂštement. Cela nĂ©cessitera des cookies, des sessions et des magasins de sessions AFAIK, mais ce n'est que le coĂ»t de crĂ©ation d'applications hybrides comme celles-ci.

Exemple d'authentification

Supposons que vous ayez une API sĂ©curisĂ©e par JWT avec deux points de terminaison d'intĂ©rĂȘt : /token et /me . /token accepte les informations d'identification par e-mail/mot de passe et renvoie un JWT signĂ© ( id_token ) tandis que /me renvoie les informations de profil relatives Ă  l'utilisateur authentifiĂ© par JWT. J'ai adaptĂ© le AuthService.js suivant du verrou d'Auth0 (en supprimant l'Ă©metteur d'Ă©vĂ©nements, bien que ce ne soit pas la pire idĂ©e). Il extrait presque tout le traitement des jetons JWT afin qu'il puisse ĂȘtre utilisĂ© sur la page de connexion et Ă©galement dans un composant d'ordre supĂ©rieur (nous en parlerons plus tard).

// 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())
  }
}

Ensuite, il y a un HOC pour simplifier la protection des pages. Pour éviter un flash indésirable d'informations sensibles, la page affichera sur le serveur Loading... lors du premier rendu pendant que React démarre / lit le jeton à partir de localStorage. Cela signifie que les pages protégées ne seront

// 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) 

La page de connexion ne peut pas utiliser le HOC tel qu'il est actuellement, car la connexion doit ĂȘtre publique. Il crĂ©e donc directement une instance d'AuthService. Vous feriez Ă©galement quelque chose de similaire pour une page d'inscription.

// ./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

InspirĂ© par les styles de rĂ©action d'Airbnb, j'ai Ă©galement commencĂ© Ă  travailler sur une next-with-auth qui serait une fonction qui renvoie un HOC Ă  utiliser sur les pages. J'ai aussi jouĂ© avec la fusion de AuthService et ce HOC. Une solution pourrait ĂȘtre de faire en sorte que ce HOC accepte une fonction de niveau d'autorisation comme argument en plus du composant, comme redux connect. Quoi qu'il en soit, dans mon esprit, vous utiliseriez next-with-auth comme ceci :

// ./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,
})

Faire tout cela avec Redux semblait inutilement compliqué, mais en gros, vous pouvez suivre l'exemple du wiki, mais déplacer AuthService dans Actions (connexion et déconnexion) et avoir un User Reducer. Cependant, vous ne pouvez appeler ces actions que sur le client, car il n'y a pas de localStorage sur le serveur, vous devez donc vérifier cela dans vos actions. En fin de compte, le magasin redux est mis sur le window toute façon. Ainsi, vous pouvez simplement mettre en cache l'utilisateur sur window au lieu d'utiliser le contexte. Si vous ne voulez pas de redux, vous pouvez également essayer react-broadcast .

Enfin, en supposant que next/server soient expédiés selon #25. next-with-auth pourrait soustraire au développeur les éléments compliqués du stockage local par rapport aux cookies avec un middleware + un HOC. Il pourrait également gérer le rafraßchissement des jetons.

Hñte d'essayer ça ! Merci pour la mise en Ɠuvre barebones :)

@jaredpalmer Je travaille sur quelque chose de similaire. Comment fonctionne votre AuthService lorsqu'un composant est rendu cÎté serveur ? Le serveur aurait besoin d'accéder au JWT mais ne peut pas le lire à partir du stockage local.

@amccloud Ce n'est pas le cas. C'est tout le problÚme. Le HOC rend <div>Loading..</div> sur les routes protégées et doit lire le jeton et décider de rediriger ou non dans componentDidMount . Pour que cela fonctionne comme vous le souhaitez et qu'il soit rendu cÎté serveur, Next a besoin de #25, ou au moins de la possibilité de définir un cookie avec la valeur du JWT AFAIK.

J'ai utilisé cookie-js pour définir un cookie, mais c'est un peu un hack.
le fait est que si vous n'envoyez pas de cookie, vous perdez tous les avantages de nextjs et du rendu cÎté serveur dans les routes authentifiées

@jaredpalmer c'est super ! Merci pour l'effort. Je vais essayer de terminer la mise en Ɠuvre de votre exemple (ou vous aider à le faire si vous le souhaitez) dans les jours suivants

Hé ! J'ai publié un exemple avec nextjs et auth0 ici : https://github.com/luisrudge/next.js-auth0
Il a le concept d'une mise en page principale et également de "pages sécurisées" qui ne se chargent que lorsque l'utilisateur est authentifié.
Dites moi ce que vous en pensez

@luisrudge incroyable. Je suis en train de cloner et de faire quelques changements mais ça a l'air super

Frais! Que pensez-vous qu'il manque? A quels changements pensez-vous ?

Le dimanche 6 novembre 2016 Ă  13:12 -0200, "Dan Zajdband" < [email protected] [email protected] > a Ă©crit :

@luisr udgehttps://github.com/luisrudge incroyable. Je suis en train de cloner et de faire quelques changements mais ça a l'air super

Vous recevez ceci parce que vous avez été mentionné.
RĂ©pondez directement Ă  cet e-mail, consultez-le sur Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687108, ou lecturehttps://github.com/notifications/unsubscribe-auth/ AA5cE8NIsvQ_ITjc1gArtFgNXzEda4TSks5q7e5NgaJpZM4KkJmi.

1) Utiliser standard pour le linting (donc c'est cohérent avec tout ce que nous construisons ensuite)
2) Ajout du support multi-onglet demandé par @rauchg
3) La partie css peut ĂȘtre simplifiĂ©e

Je t'enverrai un pr :)

Qu'entendez-vous par prise en charge de plusieurs onglets ?

Le dimanche 6 novembre 2016 Ă  13:16 -0200, "Dan Zajdband" < [email protected] [email protected] > a Ă©crit :

1) Utiliser la norme pour le peluchage (donc c'est cohérent avec tout ce que nous construisons ensuite)
2) Ajout du support multi-onglets demandé par @rauchghttps ://github.com/rauchg
3) La partie css peut ĂȘtre simplifiĂ©e

Je t'enverrai un pr :)

Vous recevez ceci parce que vous avez été mentionné.
RĂ©pondez directement Ă  cet e-mail, consultez-le sur Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687373, ou coupez le son de la

Vous avez 2 onglets ouverts, déconnexion sur 1, déconnexion automatique sur l'autre

Ahhh. C'est super cool !

Le dimanche 6 novembre 2016 Ă  13h21-0200, "Dan Zajdband" < [email protected] [email protected] > a Ă©crit :

Vous avez 2 onglets ouverts, déconnexion sur 1, déconnexion automatique sur les autres

Vous recevez ceci parce que vous avez été mentionné.
RĂ©pondez directement Ă  cet e-mail, consultez-le sur Gi tHubhttps://github.com/zeit/next.js/issues/153#issuecomment -258687707, ou coupez le son de la

Salut @luisrudge je vous ai envoyé un PR avec les changements https://github.com/luisrudge/next.js-auth0/pull/2

merci beaucoup d'avoir fait ça <3

d'ailleurs voici le résultat :

2016-11-06 11 14 31

@impronunciable @luisrudge ImplĂ©mentation fantastique ! Si vous voulez l'utiliser sans Auth0, il semble que vous n'ayez besoin de modifier que les fichiers dans le rĂ©pertoire ./utils, peut-ĂȘtre mĂȘme juste lock.js . Je vais essayer ça bientĂŽt. Au fait, le multi-onglet a l'air gĂ©nial

@ugiacoman J'ai commencé à implémenter un petit serveur avec passwordless.net, faites-moi savoir si vous voulez obtenir mon code comme point de départ

@impronunciable Ce serait génial ! J'allais faire quelque chose de similaire avec les chiffres de Twitter Fabric.

@impronuncible, je suggĂšre de ne pas utiliser le mot de passe less.net , Ă  la place, vous pouvez simplement utiliser le passeport local et simplement envoyer aux utilisateurs un lien avec leur e-mail et leur jeton dans la chaĂźne de requĂȘte.

Merci @impronunciable ❀

@ugiacoman oui, il est assez facile de supprimer la dépendance auth0. Je l'ai utilisé parce que je ne voulais pas avoir une API séparée pour gérer l'authentification

@jaredpalmer pour autant que je sache, avoir #25 serait gĂ©nial mais ne bloque pas? Je veux dire que nous avons accĂšs au cĂŽtĂ© serveur req dans getInitialProps donc rien n'empĂȘche d'y appliquer cookie-parser ? L'authentification cĂŽtĂ© serveur et la gestion de session sont toutes nouvelles pour moi 😬

BTW Ă©tant donnĂ© que localStorage ne peut pas ĂȘtre utilisĂ© cĂŽtĂ© serveur, les cookies sont-ils le seul moyen d'avoir des sessions cĂŽtĂ© serveur ? J'ai un vague souvenir que ce n'est peut-ĂȘtre pas le plus sĂ»r ? Mais y a-t-il une autre option ?

@sedubois

L'approche des cookies peut ĂȘtre trĂšs sĂ»re si elle est effectuĂ©e correctement. Faire ce qui suit est assez trivial :

  • utiliser l'indicateur httpOnly (empĂȘche l'accĂšs JavaScript au cookie)
  • utiliser un indicateur sĂ©curisĂ© (dĂ©finir un cookie uniquement pour les requĂȘtes https)
  • Cookies signĂ©s (vĂ©rifier la source du cookie)

Il existe également un avantage de latence trÚs important lorsque vous pouvez accéder aux informations d'authentification directement sur le serveur.

Nous devrions déplacer cet exemple dans examples/ Je vais voir ce que je peux trouver

J'ai réussi à utiliser react-cookie pour les cookies isomorphes en enveloppant nextjs dans un serveur express personnalisé de la maniÚre suivante :

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')
  })
})

Cela me permet de faire une demande authentifiée du cÎté serveur. Cela ne résout aucun des problÚmes des puces d'origine, mais cela a résolu le problÚme du partage de l'état entre le client et le serveur.

Du point de vue de quelqu'un qui apprend beaucoup de choses. Je pense qu'il serait préférable que les exemples ne reposent pas sur des services tiers comme auth0. Il serait plus avantageux pour les nouveaux arrivants de voir un exemple plus simple avec des formulaires de connexion/inscription et en utilisant Redux et JWT.

L'exemple que nous prévoyons de _bundle_ sera basé sur les API de serveur open source Node.js

J'ai ajouté un exemple d'authentification par e-mail à un exemple de projet de démarrage sur https://github.com/iaincollins/nextjs-starter

Il prend en charge les sessions (avec Express Sessions sur le backend et l'API de session de stockage du navigateur pour les mettre en cache sur le front-end), les cookies httpOnly, la projection CSRF, utilise SMTP intégré pour envoyer des e-mails, un backend facile à changer qui est par défaut SQL Lite . Aucune configuration n'est requise pour l'exécuter.

Le projet a Ă©galement des pages de mise en page, des itinĂ©raires personnalisĂ©s et inclut l'exemple d'horloge du wiki. Ce n'est pas l'exemple d'authentification le plus fantaisiste, mais cela peut ĂȘtre utile pour ceux qui recherchent un projet simple, facile Ă  comprendre et Ă  utiliser.

Je suis d'accord avec @iamjacks qu'un exemple avec JWT semble ĂȘtre une bonne idĂ©e.

Je suis heureux d'amĂ©liorer la gestion des erreurs et d'ajouter des fonctionnalitĂ©s comme une simple page de profil que les utilisateurs peuvent modifier, et l'intĂ©gration de passeport avec des exemples pour oAuth pour Facebook, Google et Twitter si cela peut ĂȘtre utile pour les gens. Si les gens ont de bonnes idĂ©es sur de meilleures façons de propager / exposer les informations de session aux composants, je suis trĂšs intĂ©ressĂ©.

Example screenshot showing what to expect

C'est assez incroyable @iaincollins. Nous le présenterons certainement dans les notes de version 2.0 :)

@rauchg Merci ! :)

Je suppose que je devrais ajouter explicitement que dans cet exemple, les sessions sont Ă  la fois basĂ©es sur le client et le serveur - c'est-Ă -dire qu'elles fonctionnent avec et sans JavaScript (et sur des systĂšmes sans sessionStorage), et que la mĂȘme session est partagĂ©e entre les deux.

Atteindre cela devient un peu compliquĂ© dans le composant Session, qui explore des variables avec des noms tels que req.connection._httpMessage.locals._csrf pour obtenir le jeton CSRF des en-tĂȘtes du serveur - en tant qu'objet 'req' transmis aux pages dans getInitialProps() est curieusement un peu diffĂ©rent de l'objet req exposĂ© dans Express car j'y accĂ©derais normalement via req.locals._csrf (cependant, req.session est le mĂȘme dans les deux).

localStorage n'est pas sĂ©curisĂ©. quel est le meilleur moyen de le rendre plus sĂ»r. n'importe qui peut voler les donnĂ©es de localStorage et les remettre dans son navigateur et peut ĂȘtre connectĂ© en tant qu'utilisateur victime !!

@Chathula ce n'est pas vrai. Cet argument est faux.
Si quelqu'un a physiquement accĂšs au navigateur, il peut tout faire.

C'est Ă©galement vrai pour les cookies.

L'utilisation de localStorage pour l'authentification est en quelque sorte sécurisée, car nous pourrions nous débarrasser des problÚmes de sécurité liés aux cookies.
Mais d'un autre cÎté, cela affecte la SSR.

@arunoda j'ai créé une connexion avec l'API Laravel et le client Next.js. je stocke authUser access_token dans localStorage. puis vérifiez l'utilisateur connecté ou non en vous authentifiant. mais ce n'est pas sécurisé. si quelqu'un a volé les données de localStorage. il/elle peut l'utiliser.

si quelqu'un a volé les données de localStorage.

Comment? Fondamentalement, il/elle devrait avoir accĂšs au navigateur physiquement. Alors cette personne pouvait faire n'importe quoi.
Donc, nous ne devrions pas nous inquiéter à ce sujet.

ne pouvons-nous pas utiliser de cryptage pour le rendre beaucoup plus sécurisé ?

@Chathula, cela sort du sujet. Ce n'est pas exactement pertinent pour Next.js et nous voulons suivre le fonctionnement normal des éléments Web.

@Chathula peut-ĂȘtre que vous pourriez dĂ©marrer un nouveau fil dans le projet de dĂ©marrage ci-dessus.

@arunoda hahha !! Merci pour l'info ! :RÉ

@Chathula Je suis heureux d'en discuter davantage dans un numéro du projet de démarrage si vous avez des préoccupations spécifiques.

Je voudrais corriger tout malentendu, pour éviter que les gens soient inutilement alarmés.

L'API de stockage Web (c'est-Ă -dire localStorage et sessionStorage) est - comme les cookies sans httpOnly dĂ©fini - restreinte via la mĂȘme politique d'origine (protocole, nom d'hĂŽte, numĂ©ro de port), il n'est pas vrai que "n'importe qui peut le voler" ; mais oui, si quelqu'un est capable d'exĂ©cuter du JavaScript arbitraire sur votre site via une vulnĂ©rabilitĂ© de script intersite dans votre application, il peut Ă©galement accĂ©der au magasin, vous ne devez donc pas y stocker d'identifiants de session.

C'est pourquoi vous verrez que le jeton de session lui-mĂȘme n'est pas stockĂ© dans localStorage/sessionStorage et n'est pas lisible en JavaScript, il est uniquement transmis via un cookie HTTP Only (c'est pourquoi la classe de session utilise XMLHttpRequest() plutĂŽt que fetch() - comme expliquĂ© dans la documentation de classe).

Cela signifie que mĂȘme si quelqu'un est capable d'exploiter une vulnĂ©rabilitĂ© de script intersite dans votre application et d'exĂ©cuter du code JavaScript arbitraire dans votre application Web, il ne peut toujours pas lire ou exporter un jeton de session utilisateur.

C'est peut-ĂȘtre une distinction importante qui mĂ©rite d'ĂȘtre travaillĂ©e dans la documentation.

Remarque : Un cryptage supplĂ©mentaire des donnĂ©es utilisateur n'est pas utile ici, car l'application doit toujours ĂȘtre en mesure de lire les donnĂ©es afin qu'elles puissent ĂȘtre rendues (vous devez donc Ă©galement stocker une clĂ© de description dans l'application, ce qui rendrait le cryptage du donnĂ©es utilisateur assez discutables).

_UPDATE : au cours des deux derniÚres semaines, l'exemple a été remanié pour utiliser localStorage sur sessionStorage, car sessionStorage n'est pas partagé entre les onglets et le partage de données non sensibles de cette maniÚre réduit le nombre de vérifications d'authentification inutiles et maintient l'état de la session cohérent entre les onglets._

Peut-ĂȘtre utile Ă  certaines personnes, j'ai crĂ©Ă© cet exemple d'application en expĂ©rimentant :

https://github.com/possibilités/next.js-with-auth

Soutenu par ce backend de jouet :

https://github.com/possibilités/micro-auth

Déployé ici :

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

Backend ici :

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

@possibilitĂ©s Merci Mike ! En plus d'exposer un microservice distinct qui montre une bonne façon de gĂ©rer les pages sĂ©curisĂ©es dont je pensais qu'il pourrait ĂȘtre un bon pragma et dont je pourrais m'inspirer. J'ai quelques idĂ©es qui seront soulevĂ©es dans le rĂ©fĂ©rentiel next.js-with-auth.

AprÚs avoir réfléchi davantage, je ne considérerais probablement pas mes efforts ci-dessus comme un bon exemple. Je changerais probablement pour que l'inscription/la connexion soumette entiÚrement le style Web 1.0 afin que nous puissions établir un cookie HTTP uniquement sur le serveur (éliminant l'accessibilité au JWT via XSS), puis attacher l'objet utilisateur à req plutÎt que le jeton entier. Cela laisse la possibilité de vulnérabilités CSRF mais je pense que c'est plus simple à atténuer que XSS (non ?). Un effet secondaire intéressant est que l'application cliente peut utiliser un flux presque identique lors de la connexion via un service serment.

Je vois aussi le recul , je pouvais éviter le « middleware » (et donc besoin de serveur personnalisé) en analysant le cookie dans le Page de DiC getInitialProps .

@possibilitĂ©s Étant donnĂ© que la page "secrĂšte" n'est qu'une page et qu'elle est regroupĂ©e par webpack, ne serait-elle pas servie au navigateur si j'allais Ă  /secret ?

Oui, je suppose que cela devrait ĂȘtre cĂąblĂ© pour effectuer une redirection cĂŽtĂ© serveur.

BTW, j'ai Ă©tĂ© distrait par mon projet initial de connexion avec github. Le flux est similaire avec une plus grande attention Ă  la sĂ©curitĂ© (Ă  savoir ne pas exposer de secret sur le client pour Ă©viter que le jeton oauth ne soit exposĂ© via XSS). Il est liĂ© Ă  une application appropriĂ©e, mais s'il y a un intĂ©rĂȘt, je pourrais le diviser en quelque chose qui pourrait ĂȘtre utile pour le flux oauth en gĂ©nĂ©ral.

@possibilitĂ©s Je pense que ce serait une aide formidable, s'il pouvait y avoir un PR avec un exemple avec-auth le plus minimal (mais appropriĂ©) 🙂 Je travaille sur l'authentification dans mon application (https://github.com/relatenow/ relie) mais c'est actuellement uniquement cĂŽtĂ© client (localStorage).

@sedubois J'ai un pr pour ça en utilisant passwordless.net https://github.com/zeit/next.js/pull/646 mais nous allons déplacer le serveur d'authentification ailleurs

qu'en est-il de l'utilisation de graphql ?

Apollo donne un exemple d'authentification graphql :

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

Ici, nous authentifions une requĂȘte graphql, mais elle pourrait ĂȘtre adaptĂ©e Ă  notre cas.

De plus, graphql peut faire abstraction de l'implĂ©mentation et de la logique. Il pourrait ĂȘtre utilisĂ© avec mot de passe, auth0 ou tout autre Ă©lĂ©ment que nous pourrions prĂ©fĂ©rer.

@impronunciable FYI avec votre exemple, je ne sais pas encore comment gérer les sessions, car je veux me débarrasser du sans mot de passe. Je vais essayer d'adapter l'exemple de @iaincollins dans mon application.

Mes exigences sont :

  • sĂ©curise
  • authentification cĂŽtĂ© serveur puis cĂŽtĂ© client
  • prend en charge Ă  la fois Facebook et login/mot de passe
  • les fournisseurs d'autorisation devraient ĂȘtre facilement changĂ©s
  • crĂ©er un utilisateur dans Graphcool
  • authentifier les requĂȘtes GraphQL suivantes auprĂšs de Graphcool

Au cas oĂč cela aiderait quelqu'un, voici mon application avec authentification cĂŽtĂ© serveur 🙂

L'authentification devrait ĂȘtre sĂ©parĂ©e du serveur Next.js mais j'attends que quelqu'un d'autre s'en inspire... De plus, je ne sais pas s'il est correctement protĂ©gĂ© contre CSRF.

C'est ce que j'ai fait:

  • lorsque l'utilisateur se connecte, javascript cĂŽtĂ© client dĂ©finit un cookie dans le navigateur contenant le jeton du porteur d'authentification
  • lors des demandes authentifiĂ©es, le code cĂŽtĂ© serveur (next.js) lit le jeton du porteur dans les en-tĂȘtes de la demande du navigateur et l'utilise pour contacter le serveur api au nom du client

Ceci est vulnĂ©rable aux attaques XSS (mĂȘme si React fait beaucoup pour l'empĂȘcher) et aux attaques CSRF mais c'est simple et fonctionne avec SSR.

Juste pour ajouter aux demandes

graph.cool + apollo + jwt + auth0 + next.js, les 4 premiÚres parties sont déjà faites sur https://github.com/graphcool-examples/react-apollo-auth0-example

@balupton dans votre exemple, que se passe-t-il lorsque le jeton expire alors que l'utilisateur est toujours connecté, la session vient-elle de se

@nmaro ne sais pas, pas Ă©crit par moi - il

Pour ma propre application, j'ai auth avec next.js et auth0, puis avec un serveur API zeit/micro qui vérifie les jetons du porteur.

Devrait pouvoir ĂȘtre open-source courant fĂ©vrier.

Suivant la mĂȘme philosophie que next.js (faire une chose et la faire bien), j'ai dĂ©veloppĂ© le squelette d'un systĂšme de comptes utilisateurs extensible pour node. Voir la philosophie ici : https://medium.com/the-ideal-system/ooth-user-accounts-for-node-js-93cfcd28ed1a#.97kyfg4xg

Le projet github est ici : https://github.com/nmaro/ooth/

L'objectif est d'avoir un service d'authentification + de gestion des utilisateurs extensible et indĂ©pendant qui est idĂ©al pour ĂȘtre utilisĂ© comme un microservice sĂ©parĂ©, une structure d'application qui fonctionnerait trĂšs bien avec node.js.

Un exemple avec authentification email+mot de passe est ici : https://github.com/nmaro/ooth/tree/master/examples/ooth
Il existe dĂ©jĂ  des packages pour Facebook et Google auth (ooth-facebook et ooth-google), qui devraient ĂȘtre faciles Ă  mettre en Ɠuvre sur la base respectivement de passeport-facebook et passeport-google.

Je publierai un exemple d'intégration next.js dÚs que possible. N'hésitez pas à rejoindre la discussion et à contribuer.

Désolé pour le plug, mais c'est pour le plus grand bien - je crois vraiment qu'il n'y a pas encore de bonne solution pour node, et c'est juste le bon public de personnes qui pourraient vouloir une telle chose. Paix

En attendant... voici un exemple d'API graphql qui nécessite une authentification avec un jeton JWT juste pour les opérations d'écriture. N'hésitez pas à l'utiliser avec votre méthode d'authentification préférée :)

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

J'ai mis Ă  jour https://nextjs-starter.now.sh pour ajouter le support oAuth.

screen shot 2017-02-10 at 05 03 19

  • Il utilise Passport pour oAuth, ainsi que des sessions express (comme auparavant).
  • Il existe un support pour Facebook, Google et Twitter+ oAuth et il est facile d'en ajouter d'autres (voir AUTHENTICATION.md et routes/auth-passport.js ).
  • Il utilise le systĂšme de session client/serveur universel (avec les jetons CSRF, la protection XSS via les cookies HTTP uniquement, la couche ORM qui prend en charge Mongo, les bases de donnĂ©es SQL, Redshift, etc.) comme utilisation de la connexion par e-mail.
  • Peut signaler que l'expĂ©rience de la configuration d'oAuth sur les portails de dĂ©veloppeurs est toujours aussi terrible (des erreurs Ă©tranges se produisent et il est difficile de dĂ©boguer).

La nature d'oAuth - db+sessions+passport et gestion des erreurs devant fonctionner en étroite collaboration - et des sessions devant fonctionner à la fois client et serveur et comment cela fonctionne avec le rendu universel - signifie un peu beaucoup à essayer de boucler immédiatement si vous essayez de comprendre ce qui se passe, mais la logique client n'a pas de configuration spécifique à oAuth, donc ce n'est pas trop compliqué.

Je serais heureux de séparer simplement l'authentification dans un exemple distinct, bien que je soupçonne que ce ne serait pas beaucoup plus petit. Si quelqu'un d'autre veut, tant mieux. J'ajouterai probablement un peu plus à l'exemple à un moment donné (comme une page de gestion de compte). Probablement lier plus à la documentation serait bien.

Incroyable travail! Si vous pouviez diviser l'authentification et l'ajouter au référentiel next.js, ce serait génial :heart:

Je peux le faire aussi d'ailleurs

Je n'aurai pas le temps au cours des 2 prochaines semaines, donc si quelqu'un veut le faire, ce serait génial.

J'aimerais le refactoriser et voir s'il pourrait ĂȘtre rĂ©duit Ă  un simple module (qui expose des composants simples tels que des boutons de connexion et des formulaires de connexion Ă  intĂ©grer), et m'inspirer du trĂšs bel exemple prĂ©cĂ©dent cĂŽtĂ© client uniquement par @impronunciable.

Mise à jour : en fait, je pars, c'est pourquoi je ne peux pas, mais quand je serai de retour, je serais heureux d'envisager de le faire !

J'ai suivi le guide de démarrage rapide auth0/react avec quelques modifications, mais lorsque j'appelle lock.show() , l'application se plaint :

Erreur non dĂ©tectĂ©e : addComponentAsRefTo(...) : seul un ReactOwner peut avoir des rĂ©fĂ©rences. Vous ajoutez peut-ĂȘtre une rĂ©fĂ©rence Ă  un composant qui n'a pas Ă©tĂ© crĂ©Ă© dans la mĂ©thode render un composant, ou vous avez plusieurs copies de React chargĂ©es

@iaincollins @timneutkens concernant votre exemple, veuillez me corriger si je me trompe.

L'exemple utilise un cookie httpOnly pour stocker un jeton de session le protégeant des attaques par injection javascript (XSS). Ensuite, il est difficile d'avoir un jeton csrf stocké dans le stockage local pour également se protéger contre les attaques CSRF.

Il existe une hypothĂšse sous-jacente selon laquelle cette combinaison de techniques rend les choses sĂ»res, ce qui pourrait induire en erreur l'utilisateur/dĂ©veloppeur. Un attaquant peut toujours injecter du javascript dans la page (XSS), lire le jeton csrf, et l'utiliser pour effectuer des requĂȘtes authentifiĂ©es (cookies) auprĂšs de l'apis. Vaut-il la peine d'ĂȘtre mentionnĂ© dans le readme ?

Salut @davibe

HĂ©las, il n'y a actuellement pas d'approche techniquement meilleure qu'un cookie de session et un jeton CSRF rotatif sĂ©parĂ©, alors je suppose que je dois dire que je suis globalement satisfait du modĂšle tel quel car il n'y a pas vraiment d'autre moyen de le faire (mĂȘme si la mise en Ɠuvre rĂ©elle peut toujours ĂȘtre amĂ©liorĂ©e).

Nous pourrions ajouter l'empreinte digitale du navigateur, peut-ĂȘtre que le jeton de session pourrait tourner plus frĂ©quemment (j'oublie si c'est automatique en ce moment), le jeton CSRF pourrait ĂȘtre un en-tĂȘte au lieu de param, les cookies devraient vraiment ĂȘtre SSL uniquement en production et nous pourrions ajouter une date d'expiration pour les jetons de connexion, mais pour l'AFAICS, la marge d'amĂ©lioration est assez limitĂ©e en ce qui concerne le modĂšle de sĂ©curitĂ© et rien n'accorde vraiment une protection supplĂ©mentaire au cas oĂč quelqu'un serait capable d'injecter le code de son choix dans une application ; mais s'il vous plaĂźt n'hĂ©sitez pas Ă  soulever ces choses en tant que problĂšmes pour des amĂ©liorations dans le repo.

S'il y avait des options de modification de l'état du compte (qui n'existent pas actuellement), nous pourrions avoir un CAPTCHA avant de les exécuter pour rendre plus difficile les modifications sur le serveur sans autorisation, mais tout ce qui se passe dans l'exemple est que les utilisateurs peuvent se connecter et donc c'est actuellement hors de portée.

Le stockage local des jetons de session le rendrait nettement moins sécurisé et irait à l'encontre de l'utilisation prévue dans la spécification, donc personnellement, je ne suis pas en faveur de cela - bien que j'apprécie que cela simplifierait les choses, comme l'absence de projection CSRF, mais les gens probablement je n'ai pas besoin d'un exemple de cela car ce serait trÚs simple à faire - j'ai seulement essayé d'en fournir un parce que c'est tellement maladroit. :-)

Je suis entiĂšrement avec vous dans la mesure oĂč je dĂ©teste aussi Ă  quel point c'est nĂ©cessairement maladroit et je n'ai pas renoncĂ© Ă  essayer de le transformer en module.

Hum... je comprends.
Cette question m'a été trÚs utile, merci.

C'est le point de vue d'Auth0 https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
Ils suggÚrent essentiellement d'éviter les cookies, mais cela laisserait de cÎté le SSR lors du chargement de la premiÚre page, je pense.

Salut tout le monde!

Je travaille également sur l'authentification avec next.js et les commentaires de ce numéro, en particulier @davibe + le repo de @iaincollins et le PR de @timneutkens ont été d'une aide

Ma solution fait ce qui suit :

  • Une fois la connexion rĂ©ussie, mon rĂ©ducteur redux enregistre le jeton et les donnĂ©es utilisateur dans un cookie Ă  l'aide de react-cookie .
  • Toute page / composant qui a besoin de ces informations est encapsulĂ© dans un composant d'ordre supĂ©rieur similaire Ă  @timneutkens with-session.js . Si SSR, le jeton sera disponible dans ctx.req.headers.cookie, sinon rĂ©cupĂ©rez-le simplement dans le document du navigateur (utilisez la mĂ©thode de chargement react-cookie).
  • Une fois que j'ai le jeton, je peux le dĂ©finir dans les en-tĂȘtes Bearer / Authorization chaque fois que je fais une demande.

Cela m'aide d'avoir mon propre microservice d'authentification de jeton JWT s'exécutant dans un conteneur Docker.
Peut-ĂȘtre serait-il plus facile de fournir un service JWT simple dans le cadre de l'exemple with-auth ? Évitant ainsi de pirater le server.js et de perdre potentiellement les avantages du rechargement Ă  chaud, du ssr et du routage intĂ©grĂ©s Ă  next.js ?

Je ne suis pas non plus sûr que cette approche soit sûre en termes de CSRF / XSS. Tous les commentaires sont les bienvenus.

Merci à vous tous pour le travail incroyable que vous avez fait jusqu'à présent. Je suis un grand fan de ce projet !

@jcsmesquita Je travaille sur une nouvelle version de l'exemple avec tout ce qui est sĂ©parĂ© de Next.js, de la mĂȘme maniĂšre que l'authentification est implĂ©mentĂ©e sur zeit.co.

@subsumo Merci pour la mention, FYI : NAP est à moi, l'authentification via le Web est basée sur nextjs-starter et réagit à la connexion du client natif avec un jeton.

@timneutkens la solution sur laquelle vous travaillez vous permet-elle de vous authentifier auprĂšs d'un service distinct ?

J'ai regardé l'exemple de demande d'extraction d'authentification actuelle https://github.com/zeit/next.js/pull/1141
Il me semble que cela ne permet de s'authentifier que vers le serveur next.js, mais pas de maniÚre isomorphe vers un service séparé.

En d'autres termes, supposons que vous souhaitiez séparer le serveur next.js et l'API d'application réelle (par exemple, REST ou GraphQL), alors ce que vous voulez faire est que le client et le serveur puissent s'authentifier auprÚs de l'API. Je ne pense pas que cette solution vous aide vraiment là-bas.

J'ai pensé à un flux.

Entités :

  • Client (C)
  • Serveur Next.js (S)
  • API (A)

Le but est d'établir 3 sessions basées sur des cookies :

  1. CS
  2. Californie
  3. SA

La session 1) est telle que le client reconnaßt le serveur et 2) 3) est telle que le client et le serveur peuvent utiliser leurs sessions respectives pour accéder à l'API de maniÚre indépendante.

C'est le flux :

  1. CS est facile à faire, aucune authentification nécessaire
  2. CA se fait avec authentification (par exemple avec nom d'utilisateur/mot de passe). De plus, un JWT est fourni
  3. Le client fournit JWT au serveur, puis le supprime
  4. SA est fait avec JWT, qui est ensuite rejeté

Quelle est ton opinion? Existe-t-il un moyen plus simple ? Devrions-nous plutÎt garder l'API couplée au serveur next.js, de sorte qu'une seule session soit nécessaire (CS) ?

@rauchg Je ne vous convoque pas facilement, mais je pense qu'il s'agit également de la direction que doit prendre next.js - en tant que "front-end universel", devrait-il fonctionner séparément de l'API fournissant les données ? Si oui, nous devons bien faire les choses.

@timneutkens la solution sur laquelle vous travaillez vous permet-elle de vous authentifier auprĂšs d'un service distinct ?

C'est l'idĂ©e oui. ÉtĂ© occupĂ© Ă  rĂ©parer d'autres choses sur Next.js. J'y reviendrai au plus vite.

J'ai divisĂ© les parties spĂ©cifiques Ă  github-auth de mon application en un exemple assez digeste. pourrait ĂȘtre intĂ©ressant pour certains et aimerait avoir des commentaires sur le code ou le flux : https://github.com/possibilities/next-github-auth-example

MISE À JOUR : j'ai remaniĂ© l'exemple d'application en un ensemble rĂ©utilisable de composants pouvant ĂȘtre "dĂ©posĂ©s" dans les prochaines applications

Suivi : j'ai écrit une intégration avec oooth et une API GraphQL.

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

il est basĂ© sur des approches existantes, c'est-Ă -dire l'authentification vers le serveur next.js, c'est-Ă -dire qu'il suppose que l'API et le serveur d'authentification s'exĂ©cutent tous dans le mĂȘme processus, donc une seule session doit ĂȘtre crĂ©Ă©e. L'avantage : en principe, il peut stocker les informations d'identification pour / est extensible Ă  pratiquement n'importe quelle stratĂ©gie passeport.js.

@timneutkens des progrĂšs sur ce front ?

J'ai refactorisé mon exemple d'application github auth en un ensemble réutilisable de décorateurs et de composants de page pour "déposer github auth dans" les prochaines applications. Les commentaires sur le code et les fonctionnalités sont les bienvenus. https://github.com/possibilités/next-github-auth

Je pense qu'il pourrait ĂȘtre intĂ©ressant de dĂ©finir les cartes ici, puis de continuer Ă  faire Ă©voluer cela vers un cadre d'authentification plus gĂ©nĂ©rique pour la prochaine.

@timneutkens
Désolé de vous envoyer un ping, mais avez-vous avancé sur ce point ? Je ne sais pas trop comment configurer correctement l'authentification avec next.js.

@kolpav J'ai travaillĂ© dessus, actuellement submergĂ© par d'autres trucs đŸ˜„ Bien sĂ»r, c'est assez haut sur ma liste de prioritĂ©s pour Next 😄

Un moyen clair, bien documenté et sécurisé de réaliser l'authentification avec une application next.js est essentiel à son succÚs en tant que framework.

Je ne me souviens pas de la derniÚre fois que j'ai créé un site Web sans authentification.
Comme la plupart des gens que j'imagine, je souhaite également passer des appels sécurisés à mes données sauvegardées pour le repos, donc JWT semble la solution évidente.

Mais il y a tellement de discussions entre les problĂšmes et les relations publiques que je ne sais pas par oĂč commencer !

@timneutkens
Cool 👍 Je pense que ça va ĂȘtre trĂšs prĂ©cieux pour les autres.

@camstuart @kolpav Il existe quelques bons exemples de travail ci-dessus, notamment la prise en charge de l'authentification oAuth et de l'authentification par courrier Ă©lectronique qui utilise Ă  la fois les cookies JWT et HTTP par les contributeurs @jaredpalmer , @luisrudge , @impronunciable , @possibilities et moi-mĂȘme.

Pour mettre en évidence certains liens, procédez à la vérification :

(L'exemple de micro authentification Ă©tait bon mais je pense qu'il doit ĂȘtre mis Ă  jour.)

Il existe des possibilités d'amélioration supplémentaires, que d'autres commentateurs ont commentées ci-dessus - y compris un composant de stockage de session et la division de la logique du serveur ; et un exemple qui simplifie encore plus les choses sur lesquelles Tim a travaillé.

La simplicité pour l'authentification est un domaine difficile pour les applications universelles, mais vous devriez pouvoir utiliser les exemples ci-dessus - ou simplement essayer les démos directement - et voir comment elles fonctionnent sans trop de problÚmes.

@iaincollins Ce sont d'excellents exemples. Mais comment puis-je utiliser (par exemple) un projet de démarrage ? Donc, si je veux créer mon application. J'ai besoin de cloner ce repo ? Ou j'ai besoin de "copier-coller" le code du projet de démarrage morceau par morceau dans mon propre code ?

Si le projet de démarrage est mis à jour, que dois-je faire ?

@iaincollins
De beaux exemples, surtout le vĂŽtre.
Mais quand mĂȘme, j'aimerais voir un exemple d'authentification avec le sceau d'approbation zeit dessus 😄 tous les yeux pointeraient dans une direction afin que les erreurs ou les erreurs ne passent pas inaperçues. Pour l'instant, j'ai ma propre authentification de travail, mais je ne suis pas sĂ»r de sa sĂ©curitĂ©.

D'accord @kolpav , déployer votre propre sécurité est une affaire délicate. Mieux vaut laisser aux experts

J'ai créé une pile pour cela qui peut gérer facilement l'authentification avec GraphQL : https://github.com/thebillkidy/MERGE-Stack

@salmazov J'ai trouvĂ© un moyen utile de commencer et de comprendre ce qui se passe dans un exemple ou un projet de dĂ©marrage peut ĂȘtre de le bifurquer, puis de supprimer les choses qui ne sont pas pertinentes jusqu'Ă  ce qu'il ne vous reste que le code liĂ© Ă  la fonctionnalitĂ© vous souhaitez mettre en Ɠuvre ; puis d'essayer de porter uniquement cette fonctionnalitĂ© sur un autre projet.

@kolpav @camstuart Ce fil contient une discussion trĂšs approfondie sur divers modĂšles de sĂ©curitĂ©, y compris la dĂ©mystification de certaines idĂ©es fausses et compromis courants. Je noterais en particulier les points concernant les cookies HTTP uniquement et les jetons CSRF (et la protection supplĂ©mentaire qu'ils offrent contre XSS et CSRF par rapport Ă  l'utilisation de JWT et/ou de l'API de stockage Web pour les jetons de session). Cela vaut vraiment la peine d'ĂȘtre lu.

@iaincollins Vouliez-vous lier quelque chose ? :le sourire:

Bonjour gars :)

J'ai une question, je lisais ensuite je ne peux pas obtenir les jetons pour l'authentification avec jwt de localstorage.

Si j'ai un serveur pour le rendu juste la premiÚre charge de mon site avec ensuite. Et j'ai un autre serveur pour mon api. Cela reçoit l'utilisateur/passe du client et donne un jwt. Dans quels cas dois-je obtenir le jeton sur le serveur ??

Pourquoi aurais-je besoin d'un jeton dans le serveur de rendu (suivant) ?

Si le client n'envoie pas le jeton au serveur API, l'API ne fournit pas les données et l'utilisateur ne peut pas obtenir d'informations privées. Je ne comprends pas pourquoi je dois envoyer le jeton au serveur de rendu.

@kamilml

Cela pourrait aider. En général, vous avez deux options :

  1. Donnez le prochain serveur JWT (éventuellement via un cookie). Cela permettra au serveur Next d'effectuer des appels API au nom du client. Vous voudriez cela si le rendu cÎté serveur complet est important pour vous.

  2. Stockez JWT dans le stockage local du client et n'y donnez pas accÚs au serveur Next. Dans ce cas, vous pouvez simplement contourner les appels d'API cÎté serveur et reporter le rendu complet jusqu'à ce que le chargement cÎté client soit terminé.

Toutes mes excuses pour la réouverture de ceci, mais j'ai pensé que j'ajouterais mes 2 cents à ce fil, et comment ma R&D initiale se déroule dans ce domaine. Moins d'exemples de code, plus de flux de haut niveau.

Tout d'abord, pour le contexte, la plupart de notre application est déjà intégrée à Symfony 3 (PHP) et utilise Vue pour une expérience hybride. Le serveur affiche une page wrapper et attribue les données de l'application à __INITIAL_STATE__ pour que l'application les récupÚre. Cela a conduit à prendre une décision entre le rendu des pages marketing dans Symfony (pour le référencement) et le choix de l'UX/UI plutÎt que du référencement dans d'autres domaines en récupérant les données via JS et en offrant une sensation plus SPA. Il convient également de noter que toutes les pages ne sont pas un binaire public/privé (comme je l'ai vu dans certains exemples). Certaines pages sont publiques par défaut, puis s'affichent différemment si elles sont authentifiées. Nous envisagions d'utiliser un SPA pour certaines parties du site, mais à bien des égards, c'était une pire UX/UI (TTI plus lent, barres de progression, etc.). De plus, cela ne résout pas le problÚme de référencement, à moins que nous introduisions FOUC et rendions le texte deux fois (une fois via Symfony, une fois de plus en tant que composants JS), etc.

Entrez SSR / Universal JS...

Dans mon cas, ce que j'ai fait, c'Ă©tait d'imiter la logique PHPSESSID , en crĂ©ant un cookie HttpOnly UJSSESSID (fait le nom), et en dĂ©finissant la valeur sur celle de l'utilisateur JWT. L'application Symfony transmet cela dans chaque demande de page lorsque l'utilisateur navigue sur le site. Lorsque l'utilisateur accĂšde aux pages UJS, le cĂŽtĂ© serveur de ces applications recevra les cookies dans la demande (selon le comportement intĂ©grĂ© du navigateur). Si le cookie UJSSESSID est dĂ©fini, l'application appelle l'API pour obtenir les informations de l'utilisateur (par exemple, /api/v1/users/me en passant le jeton via l'en-tĂȘte Authentication ). Le reste des appels est effectuĂ© via l'API, en utilisant le mĂȘme jeton. Le mĂ©canisme de dĂ©connexion de Symfony efface le cookie UJSSESSID . La prochaine fois que l'application UJS se chargera, les pages seront rendues en mode utilisateur anonyme. Pour info, le routage des pages Symfony vs UJS est effectuĂ© via le ProxyPass Apache. LocalStorage n'est pas utilisĂ©.

Le rĂ©sultat final est une UX transparente oĂč l'utilisateur se trouve sur certaines pages PHP avec JS cĂŽtĂ© client, et certaines pages qui sont UJS. Cela nous permet de faire des tests A/B et de mettre Ă  jour le site de maniĂšre itĂ©rative - tout le monde ne peut pas repartir de zĂ©ro :)

Bien que cela soit un peu plus compliquĂ© en raison de la symbiose PHP/UJS, le mĂȘme principe peut ĂȘtre utilisĂ© dans une solution UJS complĂšte avec une API ou un middleware de serveur Node.js (par exemple Express, Adonis, etc.). Au lieu de dĂ©finir le cookie UJSSESSID via une requĂȘte de page PHP (indicateur HttpOnly ), demandez Ă  l'utilisateur de se connecter via votre SPA/UJS et de dĂ©finir le cookie Ă  cet endroit. Ce que vous NE DEVRIEZ PAS faire, c'est d'utiliser votre application pour dĂ©coder le JWT ou de passer des appels Ă  des tiers qui nĂ©cessitent un client_secret . Utilisez un middleware qui reste sur le serveur pour cela.

J'espÚre que ça aide quelqu'un. D'autres exemples que j'ai vus étaient un peu trop en boßte de Pétri pour moi.

@jaredpalmer Hé merci pour cette implémentation, je l'ai essayé, il suffit de copier-coller tout votre code pour remplacer votre dashboard.js par mon index.js qui ressemble à ceci :

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

export default withAuth(index)

et dans withAuth hoc, je l'ai modifié pour rediriger vers la page de connexion.
Mais avant qu'il ne redirige vers la page de connexion, le contenu de la page d'index clignote encore un peu. :S

Quel est le statut de ce problĂšme ? ??

C'est un peu accablant pour les nouvelles personnes qui lisent toute la discussion. J'ai décidé d'implémenter l'authentification trÚs basique ici. Seulement 2 pages (index, login) et un serveur personnalisé
https://github.com/trandainhan/next.js-example-authentication-with-jwt

Fondamentalement, nous avons un middleware d'authentification dans le serveur pour vĂ©rifier le jeton dans l'en-tĂȘte de chaque requĂȘte. Le jeton jwt sera stockĂ© dans des cookies. Je trouve que c'est trĂšs simple, direct et fonctionne trĂšs bien.

@trandainhan Pourriez-vous ajouter un point de terminaison POST qui utilise un jeton secret pour empĂȘcher les attaques CSRF ?

@sbking Code source mis à jour avec un exemple de point de terminaison protégé par les attaques CSRF

Est-ce que c'est prĂȘt Ă  l'emploi 😬 ?

Quelqu'un a-t-il essayé l'authentification avec redux-auth-wrapper ?

Bonjour tout le monde! Au cours des derniers mois, j'ai créé, et maintenant affiné

Il comporte:

  • Inscription avec email et mot de passe
  • Connectez-vous avec email ou nom d'utilisateur et mot de passe
  • Page de compte oĂč vous pouvez dĂ©finir votre nom d'utilisateur, modifier votre mot de passe et renvoyer un e-mail de vĂ©rification
  • Mot de passe oubliĂ©/pages de rĂ©initialisation de mot de passe
  • VĂ©rifier la page e-mail
  • Une API GraphQL de base liĂ©e Ă  une MongoDB (1 fichier, peut ĂȘtre facilement supprimĂ©)
  • Passe-partout minimal (autant de logique que possible est encapsulĂ©e dans des bibliothĂšques)

Découvrez une démo en direct ici : http://staart.nmr.io/

Je l'ai fait principalement pour moi-mĂȘme pour le prototypage rapide, pour dĂ©marrer rapidement avec une application avec un systĂšme de comptes simple et fonctionnel qui ne repose pas sur des services externes. Je suis assez content des rĂ©sultats. J'ai l'intention de continuer Ă  utiliser et Ă  maintenir ces bibliothĂšques, alors essayez-le si vous pensez qu'un systĂšme de comptes Ă©tabli + une interface utilisateur pour le nƓud manque toujours.

@trandainhan Merci, c'est un trÚs bon exemple et beaucoup plus simple pour beaucoup de gens et cela fonctionnerait dans de nombreux scénarios.

Je vais rĂ©flĂ©chir Ă  si/comment je peux adapter la logique actuelle dans nextjs-starter pour utiliser quelque chose comme ça Ă  la place mais en toute sĂ©curitĂ©, tout en restant compatible avec la logique de session express pour les cas d'utilisation du monde rĂ©el que j'ai (comme utiliser des choses comme les API Google oAuth oĂč j'ai besoin que le serveur conserve et suive les jetons accordĂ©s lors de la premiĂšre connexion).

Je n'ai pas encore compris si c'est possible, mais ce serait beaucoup plus facile pour les gens si c'Ă©tait le cas.

Sinon, cela vaut au moins la peine d'écrire quelque part pour expliquer aux gens les différentes options.

@trandainhan : Si j'ajoute <Link href="/">Home</Link> dans login.js, puis que je clique sur le lien gĂ©nĂ©rĂ©, je peux alors accĂ©der Ă  index.js sans ĂȘtre connectĂ©. Comment proposeriez-vous de rĂ©soudre ce problĂšme dans votre exemple ?

@iaincollins Je vois la plupart des solutions ici s'authentifier par rapport à un service oauth. Existe-t-il une bonne solution pour s'authentifier par rapport à une API qui repose sur JWT ?

@paulwehner Je pense que cela se produit parce que @trandainhan n'a géré que le routage d'authentification cÎté serveur. Je ne sais toujours pas comment fonctionne le routage cÎté client dans next.js, car tout est géré sous le capot par le composant next/Link.

@carlos-peru Sous le capot, Link utilise en fait next/router pour insérer un nouveau chemin dans l'historique du navigateur. On dirait que la plupart des choses sont gérées par le navigateur, il n'y a rien à faire ici pour un middleware cÎté serveur. Jusqu'à présent, je ne peux penser qu'à créer notre propre composant Link et faire d'autres choses chaque fois que nous modifions l'URL.

@carlos-peru Vous pouvez toujours utiliser un serveur personnalisé pour avoir un contrÎle total sur le routage.

Merci @trandainhan et @kolpav ! J'ai pu mieux comprendre aprÚs avoir passé du temps pendant le week-end. J'ai également réussi à implémenter une solution qui repose sur HOC qui conserve le jeton jwt sur un cookie, afin que le serveur et le client puissent utiliser l'API.

@nmaro J'ai un backend avec authentification JWT pour un site Web dans next.js et une application (react-native).

Donc. Je pense au modÚle suivant : Le client obtient un token Facebook (L'utilisateur accepte le login facebook) puis le client envoie au backend le token pour vérifier et valider le token de l'utilisateur (passport-facebook-token dans node-js backend) . Ensuite, si le jeton est bon, le backend envoie au client le JWT généré dans le backend.

Le problĂšme? Votre outil peut obtenir la clĂ© de facebook et google ? J'utilise hello.js mais n'est pas compatible avec next.js et tout le monde utilise passeport-facebook. Je pense que c'est une grosse erreur car le serveur API doit ĂȘtre compatible avec le client Web et l'application mobile.

Merci

PS : je n'arrive pas Ă  obtenir une invitation dans votre chaĂźne Slack.

@hmontes here - une invitation au canal slack pour le projet oooth (comptes d'utilisateurs pour le nƓud, en particulier next.js), n'hĂ©sitez pas Ă  vous joindre. Ooth utilise passeport-facebook-token (pas passeport-facebook) et passeport-google-id-token qui, je crois, rĂ©sout votre problĂšme.

@nmaro je veux vous aider dans votre projet. J'ai un backend avec Graphql avec passeport-facebok et passeport-google-id-token aussi !!!

Mais. Connaissez-vous un package compatible pour connecter le client facebook/google dans next.js ?

CÎté client, vous pouvez utiliser un modÚle similaire à celui que j'ai utilisé ici : 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
(au lieu de oothClient.authenticate envoyez simplement une demande de publication Ă  votre route d'authentification).

@timneutkens un PR avec un exemple minimaliste serait-il le bienvenu ?

@nmaro dans votre exemple. Pourquoi utilisez-vous componentDidMount au lieu de componentWillMount ?

Je crée un composant HoC (fournisseur) pour la connexion Google.

componentWillMount est-il appelé uniquement sur le client ? Ensuite, ça devrait aller.

Bien. Merci beaucoup pour vos exemples. Enfin, je peux implémenter l'authentification avec les médias sociaux.

DerniÚre question. J'ai créé un access_token et un refresh_token et je veux mettre en localStorage pour enregistrer les données.

OĂč puis-je le mettre dans next.js pour vĂ©rifier la connexion lors de l'actualisation de la page ? Dans create-react-app, je l'ai mis dans 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}>
....

Merci

Avec oooth, je ne stocke pas les jetons facebook, je ne les utilise qu'une seule fois avec un passeport, puis je crée une session utilisateur normale basée sur les cookies.

Ah. Bien. J'utilise JWT au lieu de sessions. Donc, j'envoie access_token au backend, il vérifie si le token est valide dans le service (google, facebook), puis si l'utilisateur existe dans mon application et me renvoie un JWT.

Merci :)

Je dois ajouter qu'il est dangereux de stocker les JWT dans un stockage local (à cause de XSS), mieux vaut les envoyer en tant que cookies s'il s'agit d'un seul serveur/domaine, de sorte que le code javascript du client ne peut pas obtenir le JWT, mais le navigateur enverra le JWT automatiquement en tant que cookies. Les JWT sont délicats (voir les longues discussions ci-dessus), c'est pourquoi j'utilise également des sessions.

J'utilise un JWT uniquement si oooth est utilisĂ© comme microservice d'authentification externe (car les cookies ne fonctionnent que sur le mĂȘme domaine), et mĂȘme alors je l'utilise exactement une fois pour crĂ©er ensuite une session avec le serveur, donc il n'est stockĂ© nulle part sur le client .

Pour incrémenter la sécurité JWT, vous pouvez utiliser un jeton d'actualisation (tiré de oauth2).

Une application mobile peut gérer les cookies ?

@nmaro Okey. Je te comprends. Désolé pour mon erreur.

Avez-vous un tutoriel ou un code pour enregistrer le jeton JWT dans un cookie ? Je cherche https://github.com/zeit/next.js/blob/master/examples/with-firebase-authentication (Mon systĂšme d'authentification est avec graphql)

Non, désolé, je n'ai jamais fait ça.

@hmontes @nmaro
J'ai Ă©crit ceci pour moi, mais peut aider:
https://github.com/malixsys/mobazoo

Salut @malixsys merci pour le partage. Quelque chose que je ne comprends pas dans votre code : il semble que vous configureriez API_BASE_URL sur quelque chose d'externe, n'est-ce pas ? Si vous vous authentifiez auprÚs de cette API, je suppose que cela démarrera une session basée sur les cookies, n'est-ce pas ? Mais alors, comment transférez-vous ce cookie vers le serveur next.js, en supposant que le serveur next.js se trouve sur un autre domaine ?

Ah non, je vois, vous dĂ©finissez /auth/signin dans le mĂȘme processus. Ok, alors c'est fondamentalement la mĂȘme approche que j'ai utilisĂ©e pour oooth avec next.js / staart.

En fait non, je suis toujours confus : dans /auth/signin vous redonnez un JWT, mais vous ne faites jamais rien avec ça cĂŽtĂ© client. Plus tard, vous "getUserFromCookie" mais je ne vois pas oĂč vous avez dĂ©fini le cookie.

@nmaro Je voulais juste une connexion de base pour fonctionner avec universal initialement. J'ai tous les deux mis un jwt et un cookie pour l'instant. Le cookie est utilisĂ© pour faire universel. Je n'ai pas encore utilisĂ© le jwt dans un autre appel axios dans ce rĂ©fĂ©rentiel. Je fais dans un fork privĂ© oĂč API_BASE_URL pointe vers un autre domaine...
Tout est sur ma liste TODO, avec PWA.
N'hésitez pas à ouvrir un problÚme ou à me contacter ici...

Je sais que ce problĂšme est clos, mais j'aimerais montrer ma solution.
https://next-auth.now.sh/
Je pense que c'est un peu similaire au site de zeit.co

9 avr.

J'ai travaillĂ© dessus, actuellement submergĂ© par d'autres trucs đŸ˜„ Bien sĂ»r, c'est assez haut sur ma liste de prioritĂ©s pour Next

22 sept. #2974

Nous prévoyons de publier un exemple d'authentification officiel bientÎt, pourriez-vous le publier en tant que référentiel séparé ? Thaaanks !

@timneutkens

Salut, désolé de vous déranger à nouveau à ce sujet, mais pourriez-vous s'il vous plaßt partager comment est le statut de l'exemple d'authentification officielle ? C'est certainement quelque chose que j'aimerais voir et à en juger par le nombre de commentaires dans ce numéro d'autres aussi. Alors, quelle est sa place sur la liste des priorités et devons-nous espérer ? ??

Salut @kolpav , ils ont officiellement annoncé cela comme sur la feuille de route pour Next.js 5.

Enfin, nous ajoutons des exemples trÚs demandés (comme l'authentification des utilisateurs), une documentation améliorée pour les composants internes de Next.js, ainsi que des fonctionnalités plus petites et des corrections de bugs.

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

@babenzele C'est une excellente nouvelle. J'ai dû rater ça

OĂč pouvons-nous rester Ă  jour avec le dĂ©veloppement de Next.js 5 ? J'intĂšgre auth0 pour le moment, mais ce serait bien d'avoir un chemin / un exemple d'authentification officiel nextjs Ă  suivre

Il semble que Next.js ait dĂ©sespĂ©rĂ©ment besoin d'un exemple d'authentification locale officielle utilisant JWT/cookies/localStorage (ou une combinaison de ceux-ci, tant qu'il est sĂ©curisĂ© et protĂ©gĂ© contre XSS/CSRF)... J'ai passĂ© plusieurs semaines Ă  essayer de proposer cela en utilisant un serveur API Express sĂ©parĂ© avec une stratĂ©gie locale Passport.js. J'ai essayĂ© JWT dans un cookie/localStorage pour les demandes sans Ă©tat, et j'ai Ă©galement essayĂ© un cookie normal avec l'ID de session du middleware de session express une fois que j'ai finalement abandonnĂ© JWT et l'apatridie. J'ai fini par rencontrer des problĂšmes oĂč des sessions supplĂ©mentaires Ă©taient crĂ©Ă©es sur le serveur Express API en raison du fonctionnement de la session express (essayĂ© avec saveUninitialized: false). J'ai envisagĂ© de dĂ©placer le code Express dans server.js dans mon application Next.js, mais je prĂ©fĂ©rerais vraiment que ce soit un serveur sĂ©parĂ©. Je suis Ă©galement presque sĂ»r que mon implĂ©mentation n'est pas Ă  l'abri de XSS/CSRF ou du piratage de cookies. Nous avons besoin d'un exemple officiel qui couvre les meilleures pratiques pour l'authentification/la connexion locale, ou peut-ĂȘtre d'un module officiel dans le cadre de Next.js qui gĂ©rera les complexitĂ©s pour nous !

En attendant Next.js 5.x et d'autres exemples, vous pouvez jeter un Ɠil à https://nextjs-starter.now.sh qui est toujours activement maintenu et utilise Next.js avec Express, Express Sessions, CSRF ( CRSF Tokens), XSS (HTTP Only Cookies for session tokens) et utilise Passport JS pour prendre en charge oAuth et Email.

Je suis actuellement en train de refactoriser le code d'authentification dans un module, ce qui facilite l'ajout d'une authentification aux projets Next.js de maniÚre simple à utiliser. Le module devrait vous permettre de l'utiliser facilement avec n'importe quelle base de données que vous aimez, sans avoir à copier un tas de code à partir de l'exemple Starter Project. J'espÚre en avoir fini cette semaine.

Pour référence, la méthode "Double Submit Cookie" fournit un moyen simple d'ajouter une protection CSRF si vous recherchez une approche simple mais sécurisée.

Le problÚme avec JWT dans localStorage est qu'il est toujours lisible depuis JavaScript cÎté client, donc un vecteur pour le piratage de session via XSS, si vous avez un contenu non fiable (par exemple, du contenu ou des publicités soumis par l'utilisateur).

Si vous utilisez des cookies HTTP uniquement pour les jetons de session - ou quelque chose comme un jeton JWT avec une valeur de jeton dans un HTTP uniquement (ou cryptez l'intĂ©gralitĂ© du JWT et dĂ©chiffrez-le Ă  l'aide d'un jeton HTTP uniquement sur le serveur) - alors les sessions sont aussi protĂ©gĂ©es que possible ĂȘtre. L'idĂ©e est simplement que, idĂ©alement, les jetons de session ne devraient pas ĂȘtre lisibles via JavaScript cĂŽtĂ© client.

Bien sûr, de nombreux sites n'utilisent pas de cookies HTTP uniquement, car c'est pénible pour les applications à page unique et implique invariablement d'avoir une logique d'authentification dans le front-end, mais c'est toujours l'approche idéale.

Une autre option est toujours https://github.com/nmaro/ooth qui est activement maintenue, est déjà fournie dans des packages et est utilisée dans quelques applications de production.

@iaincollins J'ai tĂ©lĂ©chargĂ© Next.js Starter Project et j'ai commencĂ© Ă  le parcourir. Je devrai sĂ©parer les parties importantes liĂ©es Ă  la sĂ©curitĂ© (XSS/CSRF) et essayer de les intĂ©grer dans mon application, ou attendre la fin du module sĂ©parĂ©. Y a-t-il un endroit oĂč je peux suivre le dĂ©veloppement de ce module ?

Salut @kelleg1 ,

Le module séparé est maintenant publié en tant que module d' autorisation suivante pour faciliter son utilisation dans d'autres projets. Il comprend un exemple de projet qui montre comment l'utiliser.

Pour plus de référence, le projet nextjs-starter.now.sh utilise désormais également next-auth, ce qui simplifie grandement le code dans le projet de démarrage - et il est désormais beaucoup plus facile d'ajouter la prise en charge de nouveaux fournisseurs oAuth ou de l'utiliser avec différentes bases de données ( bien que l'exemple utilise toujours Mongo DB).

C'est quand mĂȘme un peu compliquĂ©, donc si vous avez une application existante, vous la trouverez peut-ĂȘtre plus facile Ă  utiliser comme rĂ©fĂ©rence, mais si c'est le cas, j'espĂšre que cela vous aidera

NB : CSRF y est actuellement encore assez étroitement couplé. Il utilise Lusca et suppose donc que res.locals._csrf est défini, mais différentes bibliothÚques CSRF utilisent différentes vars privées.

J'apprécie que c'est toujours plus compliqué à utiliser que quiconque ne le voudrait tel quel, mais au moins maintenant, le code d'authentification est enfin séparé en un module afin que je puisse commencer à refactoriser. J'espÚre le rendre plus facile à utiliser (avec des gestionnaires par défaut pour différentes bases de données et une configuration plus facile d'oAuth) au fil du temps.

@iaincollins, il semble que la seule dépendance sur next.js soit https://github.com/iaincollins/next-auth/blob/master/index.js#L342 ? Si c'est le cas, ce serait formidable de rendre la lib next.js-agnostic.

@sedubois Tout Ă  fait d'accord !

Bien que ce soit probablement une bonne discussion pour ses problĂšmes de repo GitHub plutĂŽt qu'ici. 🙂 Si vous souhaitez suggĂ©rer des moyens d'amĂ©liorer, de simplifier et de rendre plus gĂ©nĂ©rique, vous aimeriez collaborer.

(Avoir quelque chose d'aussi facile Ă  utiliser que possible avec Next est toujours un objectif principal, mais je ne pense pas qu'il doive ĂȘtre exclusif, mĂȘme s'il se termine Ă©galement par les prochaines options ciblĂ©es spĂ©cifiques.)

@timneutkens Félicitations pour la sortie de nextjs 5. Dans un avenir proche, verrons-nous l'ajout d'un exemple officiel d'authentification locale au dossier des exemples ? Ou est-ce quelque chose encore en préparation pour une version ultérieure ?

Ooth dispose désormais d'une documentation complÚte, comprenant les spécificités de l'authentification next.js.

@jaredpalmer J'aime votre approche, j'ai copié des parties de votre implémentation. Cependant, la méthode getUser sûre ? Que se passe-t-il si quelqu'un modifie manuellement la chaßne dans le stockage local, serait-il intelligent pour l'application de s'appuyer sur cela ? Serait-il plus logique de le changer en méthode qui décode la partie publique du jeton JWT à chaque fois et lit l'état de l'utilisateur à partir de là ? De cette façon, nous pouvons faire davantage confiance à cet état en raison de la nature JWT des choses. Quel est ton opinion?

Vous devriez le stocker dans un cookie. J'ai écrit cela avant que Next ne prenne en charge les serveurs personnalisés.

@jaredpalmer Pouvez-vous m'en dire plus ? Devrions-nous tout stocker dans des cookies plutÎt que dans un stockage local ? Votre HOC serait-il différent aussi ? Cela signifie-t-il que nous pouvons maintenant utiliser la méthode getInitialProps pour le rendu cÎté serveur des sites Web protégés ?

Juste un avertissement _si vous parlez de stockage de données sensibles dans un stockage local/stockage Web_ :

"Ne stockez jamais de données sensibles à l'aide du stockage Web : le stockage Web n'est pas un stockage sécurisé. Il n'est pas « plus sécurisé » que les cookies car il n'est pas transmis par cùble. Il n'est pas crypté. Il n'y a pas d'indicateur sécurisé ou HTTP uniquement, donc cela n'est pas un endroit pour garder une session ou d'autres jetons de sécurité."

DĂ©finissez le jeton dans un cookie aprĂšs la connexion. utiliser cookie-js. Ensuite, utilisez l'analyseur de cookies express sur le serveur afin de pouvoir rechercher get req.headers.cookies.myToken ou Ă©quivalent. Dans getInitialProps d'un hoc, vĂ©rifiez si req existe, puis rĂ©cupĂ©rez le jeton Ă  partir de req.cookies, sinon rĂ©cupĂ©rez-le sur le client Ă  partir de Cookies.get('mytoken'). À ce stade, vous aurez accĂšs Ă  votre jeton sur le client et le serveur. Ensuite, vous voulez crĂ©er un wrapper/instance fetch/axios et le fusionner avec le ctx de next dans getInitialProps afin que toutes vos pages aient un moyen de faire des demandes isomorphes authentifiĂ©es. Vous voudrez peut-ĂȘtre aussi simplement faire participer votre utilisateur au hoc. Vous n'avez donc pas besoin de rĂ©pĂ©ter cela partout. Vous pouvez ensuite faire plus de hoc si vous en avez besoin pour des entitĂ©s communes comme withUser(withTeam(Page))

getUser est une mauvaise idée, vous ne devez stocker que le jeton.

@jaredpalmer J'ai construit une approche presque exactement comme ça et tout fonctionne bien. Le problÚme que j'essaie de résoudre maintenant est de savoir comment actualiser les jetons. L'API avec laquelle je travaille a des jetons de durée relativement courte (2 heures) et j'essaie de me familiariser avec un systÚme pour garder l'utilisateur connecté tout en utilisant l'application.
Avez-vous une contribution lĂ -dessus?

Vous pouvez Ă©galement enregistrer une demande Ă  chaque transition de page en ne transmettant pas de donnĂ©es via next.js pour votre utilisateur. Pour ce faire, vous devez lire le jeton du cookie dans server.js et tenter de rĂ©cupĂ©rer l'utilisateur et le transmettre au gestionnaire de requĂȘtes suivant. Dans le document, rĂ©cupĂ©rez-le Ă  partir de props et stockez-le dans JSON comme window.USER. Ensuite, dans votre hoc, vous le lisez simplement depuis la fenĂȘtre lorsque vous ĂȘtes dans la zone client. Enfin, vous devez utiliser axios avec un intercepteur de rĂ©ponse qui efface immĂ©diatement votre cookie Ă  la rĂ©ception du code 403 et recharge la page

@pbrandone Bien que rĂ©pĂ©titive, la solution la plus simple et la plus prĂ©visible consiste Ă  envoyer votre jeton Ă  chaque demande, en recevant un jeton nouvellement actualisĂ© dans l'en-tĂȘte/le corps de la rĂ©ponse. Votre client met Ă  jour sa valeur connue Ă  chaque cycle de demande/rĂ©ponse, accordant effectivement des jetons Ă  usage unique qui ne sont jamais pĂ©rimĂ©s et ne peuvent pas ĂȘtre utilisĂ©s Ă  mauvais escient.

En rÚgle générale, avec cette approche, le /token/refresh n'est utilisé que pour le "réveil" initial de l'application (pensez au crochet componentWillMount pour <App/> ), en vérifiant si le dernier le jeton est toujours valide et utilisable.

Je n'ai jamais eu Ă  gĂ©rer les jetons de rafraĂźchissement, mais j'essaierais probablement de le faire dans un intercepteur axios. Il faudrait y rĂ©flĂ©chir davantage, mais en thĂ©orie, vous intercepteriez une mauvaise demande, puis utiliseriez le jeton d'actualisation pour obtenir un nouveau jeton, dĂ©finiriez le cookie avec le nouveau jeton et rejouerez la premiĂšre demande avec le nouveau jeton. Les intercepteurs Axios sont vraiment puissants car ils vous permettent de garder des Ă©lĂ©ments comme celui-ci abstraits et hors de vue de votre code produit. Vous devrez peut-ĂȘtre Ă©crire un intercepteur de demande et de rĂ©ponse et/ou conserver une sorte d'objet/carte avec Ă©tat en cours qui pourrait devenir velue. EspĂ©rons que cela aide

Ou fais ce que Luke a dit. Beaucoup plus facile.

Si vous souhaitez actualiser les jetons, vous devrez intercepter le cookie (si vous utilisez des cookies) via une configuration de serveur personnalisĂ©e. Je l'ai fait en utilisant express. Sinon, vous pouvez tout faire cĂŽtĂ© client en utilisant des jetons JWT. Depuis que je faisais le mien via des cookies, j'ai eu 2 cas d'utilisation - gĂ©rer les demandes de navigation cĂŽtĂ© client et les demandes de page cĂŽtĂ© serveur (Ă  chaque fois que quelqu'un tape manuellement une URL ou appuie sur l'actualisation de la page.) Mais fondamentalement, ils sont le mĂȘme flux juste exĂ©cutĂ© diffĂ©remment puisque l'un est cĂŽtĂ© client et l'autre cĂŽtĂ© serveur. CĂŽtĂ© serveur, depuis que j'utilise express, je viens de crĂ©er un middleware pour traiter le cookie, dĂ©coder le JWT qu'il contient et vĂ©rifier l'expiration. S'il a expirĂ©, faites une demande pour obtenir un nouveau jeton et continuez Ă  transmettre l'utilisateur dĂ©codĂ© Ă  redux sur le client. Sur le client, j'ai un wrapper HOC pour les liens sĂ©curisĂ©s qui vĂ©rifie constamment l'utilisateur, chaque fois que vous naviguez quelque part sur le client. Le HOC obtiendra votre cookie ou JWT (dans mon cas, mon JWT est dans un cookie) et vĂ©rifiera s'il est toujours valide rapidement. S'il n'est pas valide, il essaiera d'obtenir un JWT/Cookie actualisĂ© et continuera, sinon il vous dĂ©connectera. Oui plus compliquĂ©, mais aussi plus sĂ©curisĂ©. J'espĂšre que cela pourra aider! N'hĂ©sitez pas Ă  poser des questions si cela vous intĂ©resse - il m'a fallu un certain temps pour tout comprendre. Personnellement, je me pose des questions sur les personnes qui se connectent avec Github ou FB, etc. - probablement ok dans de nombreux cas, mais dans certains cas, ce n'est tout simplement pas professionnel. Je n'ai pas encore vu de banque, de soins de santĂ©, aucune de mes factures que je paie, etc. - connectez-moi avec mon compte FB. Ce n'est peut-ĂȘtre qu'une question de temps ;)

En ce qui concerne le rafraßchissement des jetons d'accÚs ;
Je ne sais pas si c'est une bonne façon de le faire, mais mes jetons d'accÚs sont de trÚs courte durée (une minute environ). Pour traiter les problÚmes d'expiration des jetons cÎté client, j'ai adopté cette approche ;
Chaque fois qu'une page est chargée, il vérifie si le jeton a expiré, si c'est le cas, il l'actualise. Cependant, s'il est toujours valide, il appelle une méthode qui vérifie le délai jusqu'à l'expiration et définit le délai d'expiration qui actualisera le jeton d'accÚs à l'expiration. Et puis répÚte ce processus tant que le visiteur est sur le site.

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

Cela renvoie des millisecondes jusqu'à l'expiration :

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

Tout retour sur cette approche serait le bienvenu

@kunokdev - Je pense que c'est un bon dĂ©but. J'ai dĂ©placĂ© une fonction similaire, je devais calculer le temps restant vers une fonction qui renvoyait simplement un boolĂ©en selon qu'il Ă©tait expirĂ© ou non et cela rendait mon code un peu plus lisible et simple et je n'avais pas Ă  me soucier de la rĂ©initialisation des minuteries. Ensuite, je vĂ©rifie simplement si l'utilisateur a expirĂ© ou non sur toute sorte de demande nĂ©cessitant une authentification. Si j'avais un compte Ă  rebours ou quelque chose comme celui qui Ă©tait visible pour le client ou le dĂ©bogage, votre fonction serait idĂ©ale. C'est mes 2 centimes 👍

L'exemple auth/login ne devrait-il pas ĂȘtre le plus basique possible ? c'est-Ă -dire un magasin de mĂ©moire et pas de JWT ou de jetons Ă©tranges. Habituellement, lorsque vous pensez Ă  quelqu'un "connectĂ©", cela signifie qu'il a un cookie/une session active.

J'ai une connexion HOC qui fonctionne cĂŽtĂ© client et serveur. Il utilise un JWT et un backend (peut ĂȘtre node, django, peu importe).

Vérifiez-le et tout commentaire est trÚs apprécié

https://github.com/hugotox/AppStarter

Code pertinent ici https://github.com/hugotox/AppStarter/blob/master/src/components/auth/login-required.js

@hugotox J'aime l'idĂ©e d'utiliser le magasin Redux pour stocker les donnĂ©es d'authentification, mais lorsque vous appelez store.dispatch partir de getInitialProps plusieurs fois, soyez prĂȘt pour les effets secondaires indĂ©sirables, lorsque le composant dĂ©corĂ© sera rendu mĂȘme si le processus d'authentification n'est pas encore fini. Prenons un exemple d'utilisation de votre code :

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

Dans getInitialProps vous appelez verifyToken avant verificationOk , donc MyPage.mapStateToProps sera appelĂ© 2 fois (s'il Ă©coute store.auth.user) et la premiĂšre fois store.auth.user sera nul mĂȘme pour une page nĂ©cessitant un utilisateur connectĂ©.

Hier, j'ai également publié la premiÚre version WIP de mon propre kit de démarrage alimenté par Next.js, mais j'ai commencé avec Docker, Flow et fast-redux : https://github.com/dogada/microchain

J'utilise des images Docker dédiées pour le serveur API et l'application Web pouvant s'exécuter sur différents domaines. Je recherche donc toujours une solution fonctionnelle qui permettra de connecter de vrais utilisateurs mais également d'émettre des jetons de support OAuth pour les clients mobiles par exemple.

@spencersmb excellent

@james-ff Merci d'avoir postĂ© cela, mĂȘme si cela donne l'impression de crier dans le vide.

Cela a Ă©tĂ© dit plusieurs fois dans ce fil, mais tout le monde ignore apparemment encore qu'il ne devrait pas stocker de jetons de session dans JWT avec localStorage ou dans des cookies accessibles en JavaScript et semble vouloir essayer de rĂ©inventer les sessions et l'authentification de maniĂšre moins sĂ©curisĂ©e. (et cela nĂ©cessite JS cĂŽtĂ© client). đŸ™ƒđŸ€ŠđŸ»â€â™‚ïž

L'auteur de cet article a rĂ©digĂ© un excellent article sur ce qui ne va pas en 2016, mais malheureusement, les choses ne semblent pas s'ĂȘtre amĂ©liorĂ©es :

Malheureusement, il semble que j'aie trouvĂ© la limite supĂ©rieure de la longueur des articles avant que les gens arrĂȘtent de lire - de nombreux commentateurs sur Reddit et Hacker News n'arrĂȘtaient pas de suggĂ©rer les mĂȘmes "solutions" encore et encore, ignorant complĂštement qu'elles Ă©taient dĂ©jĂ  abordĂ©es et jugĂ©es peu pratiques dans l'article lui-mĂȘme.

L' article d'origine et le diagramme de suivi sont tous deux trĂšs bons.

Les JWT @iaincollins et les applications/authentification sans session ont leurs avantages et de nombreuses personnes/entreprises (y compris Google) souhaitent toujours les utiliser. AprĂšs avoir lu le cas contre les JWT , je pense toujours qu'il devrait y avoir deux exemples/bibliothĂšques officiels de next-auth, l'un utilisant des sessions (comme next-auth) et l'autre utilisant des JWT, ou peut-ĂȘtre juste un qui permet d'utiliser l'un ou l'autre. Les avantages, les inconvĂ©nients et les mises en garde doivent ĂȘtre clairement expliquĂ©s pour chacun sur les pages de tutoriel officielles Next.js et/ou la documentation du module quelque part. Jusqu'Ă  ce que quelqu'un invente un meilleur standard/bibliothĂšque, je continuerai probablement Ă  utiliser nextjs-starter et next-auth, car ce sont les meilleurs que j'ai trouvĂ©s.

Je n'ai gardĂ© qu'un Ɠil sur cela, mais mon expĂ©rience avec l'authentification JS universelle consiste Ă  stocker un JWT dans un cookie HttpOnly . Il n'y a vraiment aucune raison d'utiliser localStorage lorsque vous avez la possibilitĂ© d'utiliser le cĂŽtĂ© serveur de l'application pour stocker le cookie. Si vous avez besoin d'accĂ©der au JWT pour les appels d'API cross-origin dans le navigateur, vous pouvez alors passer le JWT dans un scĂ©nario de type __INITIAL_STATE__ (attention aux vulnĂ©rabilitĂ©s XSS, mais au moins vous ne « stockez » cĂŽtĂ© client). Pour un accĂšs de mĂȘme origine, le cookie sera transmis dans les deux sens (en supposant que vous utilisez withCredentials pour axios, ou credentials: 'include' pour rĂ©cupĂ©rer), Ă©liminant ainsi la nĂ©cessitĂ© de mettre le JWT dans JS du tout . Vous pouvez utiliser un proxy cĂŽtĂ© serveur de l'application pour extraire le JWT du cookie HttpOnly , _puis_ Ă©galement effectuer vos appels d'API cross-origin. Vous annulez Ă©galement l'appel de contrĂŽle en amont dans ce scĂ©nario. À chacun ses goĂ»ts, mais personnellement, je ne pense pas que localStorage soit nĂ©cessaire pour les applications universelles.

@bjunc Oui, parmi toutes les options concernant l'emplacement de stockage d'un JWT (localStorage vs. HttpOnly cookie vs. Redux, ou autre), je me trompe peut-ĂȘtre, mais je pense que la rĂ©ponse devrait toujours ĂȘtre un cookie HttpOnly. Cela semble avoir Ă©tĂ© dit d'innombrables fois sur de nombreux blogs et forums. (Je ne suis pas sĂ»r des jetons d'actualisation - ils devraient peut-ĂȘtre aussi ĂȘtre stockĂ©s dans un cookie HttpOnly ?)

J'ai essayĂ© de faire plus ou moins exactement ce que vous avez dit dans un de mes projets avant de commencer Ă  adopter nextjs-starter et next-auth. Cela fait un moment, mais si je me souviens bien, je pense que le problĂšme que j'ai rencontrĂ© Ă©tait que mon serveur Express API contre lequel je m'authentifiais (qui utilisait express-session) n'initialisait/rĂ©cupĂ©rait pas correctement la session. J'obtiendrais un comportement Ă©trange oĂč les sessions seraient initialisĂ©es plusieurs fois. J'ai l'intention de recommencer Ă  faire plus ou moins ce que vous avez dĂ©crit si je peux rĂ©soudre ce problĂšme. Je continuerai Ă©galement Ă  travailler avec nextjs-starter et next-auth, car les sessions Ă©liminent bon nombre des autres problĂšmes posĂ©s par les JWT, tels que la façon d'invalider les jetons.

Encore une fois, un exemple officiel (ou des exemples) serait utile. Mot clé : officiel, signifiant que les auteurs de Next.js ont envisagé toutes les possibilités et y ont intégré les meilleures idées et pratiques. Idéalement en utilisant les fonctionnalités ES6/ES7/ES8 modernes telles que les promesses et async/wait.

@kelleg1 il semble que vos problĂšmes soient liĂ©s aux spĂ©cificitĂ©s de la crĂ©ation de cookies. Par exemple, vous pouvez crĂ©er accidentellement plusieurs cookies avec le mĂȘme nom en utilisant des paramĂštres diffĂ©rents ( HttpOnly , domaine, chemin, expiration, etc.); ce qui pourrait crĂ©er des effets secondaires Ă©tranges comme vous le dĂ©crivez. Une façon de dĂ©boguer consiste Ă  utiliser les outils de dĂ©veloppement Application->Cookies. Si vous voyez un tas de cookies portant le mĂȘme nom, cela pourrait vous orienter dans la bonne direction.

Quoi qu'il en soit, je ne fais pas partie de l'Ă©quipe de base, donc je ne peux pas aider avec une contribution "officielle" (et en fait, j'utilise Nuxt.js, pas Next.js), mais les principes sont les mĂȘmes. J'ai expĂ©rimentĂ© diffĂ©rentes maniĂšres de procĂ©der (peser le pour/le contre de JWT, cookies, CSFR, websocket CSWSH, localStorage, etc.). Je suis finalement arrivĂ© Ă  la conclusion que la nature universelle de Next/Nuxt se prĂȘtait bien Ă  l'utilisation de cookies JWT HttpOnly . Peut-ĂȘtre que d'autres arriveraient Ă  une conclusion diffĂ©rente, mais personnellement, je ne suis pas dans le camp du "oh mon Dieu, n'utilise pas JWT, n'as-tu pas lu cet article qui dit que JWT vous donne le cancer ! ?".

@iaincollins dĂ©solĂ© de ramener cela Ă  nouveau, mais chaque didacticiel sur le Web utilise localStorage pour enregistrer le jeton et vous dites qu'il n'est pas sĂ©curisĂ©. Si oui, oĂč sommes-nous censĂ©s stocker le jeton ?

BISCUITS! :RÉ
nous utilisons quelque chose comme ceci :

// 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({...});

Un peu kludgy mais assez sécurisé car javascript cÎté client ne voit jamais de jeton et le cookie est httpOnly, sécurisé, signé et envoyé automatiquement par axios ou autre...

Salut à tous, je viens de créer un exemple d'authentification avec cookies et redux. Voir ici https://github.com/zeit/next.js/pull/4011

Attendez, alors oĂč ce problĂšme s'est-il terminé ? Je n'ai jamais pu trouver d'exemple d'authentification Express dans le rĂ©fĂ©rentiel officiel.

Je vois beaucoup de discussions sur les cookies et les sessions, mais comment cela fonctionne-t-il pour mon application mobile native lorsqu'elle doit accéder à l'API ?

@jackjwilliams les bibliothÚques HTTP des applications mobiles ne devraient-elles pas également prendre en charge les cookies ?
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

C'est possible, mais c'est à ça que sert JWT :p

Je viens de faire une lecture détaillée de tout ce fil et je me sens obligé de résumer mes conclusions.

Il semble qu'il existe deux projets de démarrage viables avec des modules d'authentification solides pris en compte :

Excellent travail de @iaincollins et @nmaro !

Merci @curran :)

J'ai documenté toutes les modifications de code que j'ai apportées pour éliminer les aspects superflus de nextjs-starter dans cette Pull Request https://github.com/iaincollins/nextjs-starter/pull/86

Cela peut se rapprocher d'un exemple d'authentification solide et simple pour le référentiel Next.js.

J'avais rĂ©cemment besoin d'implĂ©menter OAuth avec Office 365, j'ai donc pensĂ© partager un exemple trĂšs simple que j'ai rassemblĂ© ici . Il a besoin de travail (et est loin d'ĂȘtre aussi dĂ©veloppĂ© que certains des exemples ci-dessus), mais je pense qu'il pourrait Ă©ventuellement ĂȘtre gĂ©nĂ©ralisĂ© pour utiliser Ă©galement divers clients OAuth. Il utilise plusieurs des exemples dĂ©jĂ  prĂ©sentĂ©s dans le rĂ©fĂ©rentiel d'exemples Next.js ainsi que le thread de routes protĂ©gĂ©es ici . Dans tous les cas, je viens de penser que je partagerais au cas oĂč quelqu'un voudrait un exemple rapide de la façon (peut-ĂȘtre) de le faire avec Microsoft.

Pour toute personne intéressée par une simple authentification à jetons JWT qui fonctionne cÎté client et cÎté serveur, j'ai obtenu de l'aide dans le chat Spectrum et j'ai pensé que je la partagerais avec vous tous. Tout commentaire est toujours apprécié.

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

Salut les gars!
Voici un autre exemple d'authentification avec next.js que j'ai construit il y a quelques mois, peut-ĂȘtre que quelqu'un le trouvera utile :

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

Ooth 2.0 est sorti avec de nouveaux et meilleurs documents

Ooth est un systÚme de gestion de l'identité des utilisateurs conçu pour node.js (en pensant à next.js).

Stratégies actuellement prises en charge :

  • Primaire : nom d'utilisateur/mot de passe (y compris vĂ©rifier l'e-mail, mot de passe oubliĂ©, etc.), invitĂ©, facebook, google
  • Secondaire : sessions basĂ©es sur les cookies, JWT

DĂ©couvrez cet exemple en direct qui rassemble tout avec next.js ( code source ).

De nombreux exemples d'authentification ici (et dans le dossier des exemples) renvoient la session/jeton/etc de l'utilisateur à partir de getInitialProps . Autant que je sache, lorsque la page est rendue cÎté serveur, cela signifie que les informations de session utilisateur seront envoyées dans le cadre de la réponse de la page HTML (dans le cadre de NEXT_DATA ) au navigateur.

Je vois deux problÚmes de sécurité avec ce modÚle lorsque getInitialProps est exécuté cÎté serveur :
1) La session utilisateur est transmise sur le rĂ©seau du serveur au navigateur. Si de telles requĂȘtes utilisent http:// et non https:// , le jeton de l'utilisateur, etc. serait exposĂ© sur le rĂ©seau en texte brut.

2) La session utilisateur est renvoyĂ©e du serveur au navigateur dans le cadre de la page HTML (dans une balise de script NEXT_DATA ). Avoir le jeton/etc de l'utilisateur directement sur la page HTML semble risquĂ©, surtout une fois que la page est analysĂ©e, rendue par le navigateur et que d'autres scripts tiers peuvent maintenant ĂȘtre en cours d'exĂ©cution.

Ces problÚmes ont-ils déjà été traités ? Existe-t-il des mesures d'atténuation pour ces menaces ?

C'est pourquoi j'utilise des cookies. Voir mon exemple ici https://github.com/hugotox/nextjs-starter/blob/master/pages/_app.js

Finalement! Vous trouverez ici un exemple d'authentification next.js entiÚrement dockerisé avec les conteneurs suivants :

  • suivant.js
  • microservice d'authentification (ooth)
  • api (graphql)
  • stockage de session (redis)
  • petit proxy inverse

Tout est rassemblé avec docker-compose.

Note rapide sur les JWT. Les JWT ont l'avantage d'ĂȘtre sans Ă©tat, bons pour les mobiles et bons si vous devez transmettre des informations d'identification d'un domaine Ă  l'autre. Le principal inconvĂ©nient est qu'ils exposent le navigateur Ă  XSS. Pour cet exemple, j'ai optĂ© pour une solution purement basĂ©e sur les sessions de cookies. J'ai quand mĂȘme rĂ©ussi Ă  diviser les choses en microservices grĂące au proxy inverse (tous les microservices s'exĂ©cutent sous le mĂȘme domaine) et au stockage de session partagĂ©.

https://github.com/nmaro/staart/tree/master/examples/staart
L'exemple en direct est, comme d'habitude : https://staart.nmr.io

Je pense qu'il est prudent de prĂ©ciser que l'utilisation de JWT ne vous « expose » pas intrinsĂšquement Ă  XSS. Au contraire, si votre site prĂ©sente une vulnĂ©rabilitĂ© XSS (non due au JWT lui-mĂȘme), un JWT pourrait ĂȘtre compromis (ainsi que toute autre information accessible par script) ; alors que les cookies httpOnly ne seront pas accessibles. Peu importe que vous puissiez utiliser un JWT comme valeur d'un cookie httpOnly !

Les solutions de cookies uniquement peuvent bien fonctionner pour la communication avec le mĂȘme domaine, mais si vous avez une API sans tĂȘte (par exemple, example.com appelant api.example.com ), alors ce n'est pas vraiment une solution Ă  moins que vous ne vouliez un navigateur proxy. demandes de example.com Ă  api.example.com en effectuant vos appels API Ă  example.com et en les transfĂ©rant avec le cookie ajoutĂ© Ă  la demande (qui vient avec son propre ensemble d'avantages/inconvĂ©nients) .

Personnellement, je pense que les inconvĂ©nients de JWT sont largement exagĂ©rĂ©s et sont assez facilement attĂ©nuĂ©s par une multitude de protections couramment mises en Ɠuvre. Notamment, une liste noire de jetons rĂ©fĂ©rençant la rĂ©clamation jti (par exemple, l'UUID Version4) dans le cas oĂč le jeton a Ă©tĂ© compromis avant son expiration.

Hey @bjunc oui merci d'avoir clarifiĂ©. Correct, JWT ne vous expose pas lui-mĂȘme Ă  XSS. Concernant vos autres observations, j'aimerais ajouter qu'elles ont chacune leurs piĂšges.

Peu importe que vous puissiez utiliser un JWT comme valeur d'un cookie httpOnly !

Oui, j'aimerais juste ajouter que cela supprime le seul avantage de JWT de transférer les informations d'identification entre les domaines.

une liste noire de jetons

Cela, et l'autre pratique courante d'un jeton d'actualisation, suppriment l'autre avantage de JWT d'ĂȘtre vraiment sans Ă©tat.

Voici ma compréhension de la situation :

  • Si vous avez besoin d' une authentification croisĂ©e, utilisez JWT <- mais Ă©vitez si possible pour des raisons de sĂ©curitĂ©
  • Si vous devez vous authentifier Ă  partir d'un client qui n'est pas un navigateur et qui n'a pas le problĂšme XSS (par exemple, une application de bureau ou mobile), utilisez JWT
  • Sinon, utilisez des sessions basĂ©es sur des cookies, car une solution basĂ©e sur JWT sera soit moins sĂ©curisĂ©e (XSS), soit ne sera pas vraiment sans Ă©tat (listes noires), ou vous obligera Ă  utiliser un proxy pour tout garder sous le mĂȘme domaine de toute façon.

J'ai Ă©crit un article Medium sur Next.js Authentication/User account.
C'est un tutoriel complet et mon braindump de prÚs de deux ans de développement et de réflexion pendant mon temps libre (mon premier commentaire sur ce problÚme date de février 2017).

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

Vous continuez Ă  corrĂ©ler JWT avec moins de sĂ©curitĂ©. JWT ne rend pas votre site moins sĂ©curisĂ©. Ce n'est pas en soi une vulnĂ©rabilitĂ© XSS. Si vous avez un exploit XSS, vous ĂȘtes malgrĂ© tout dans le mĂȘme pĂ©trin. MĂȘme avec un cookie httpOnly , l'attaquant peut ne pas ĂȘtre en mesure de lire la valeur du cookie, mais cela n'a pas d'importance car il peut exĂ©cuter du code arbitraire - comme les requĂȘtes XHR qui transmettraient automatiquement les cookies de session (agissant essentiellement comme une attaque CSRF). Si votre API est interdomaine et que vous effectuez des requĂȘtes navigateur-serveur, le JWT se trouve de toute façon quelque part dans le code (que ce soit l'Ă©tat initial ou localStorage). Si vous utilisez Axios, vous avez peut-ĂȘtre mĂȘme dĂ©fini des valeurs par dĂ©faut globales, oĂč l'attaquant n'a qu'Ă  faire une requĂȘte Axios sans mĂȘme se soucier de l'authentification.

De plus, vous ne pouvez pas vraiment parler de XSS sans parler Ă©galement de CSRF ; oĂč les cookies d'autorisation sont spĂ©cifiquement ciblĂ©s. MĂȘme avec une configuration de proxy inverse, une attaque CSRF permettrait Ă  l'attaquant d'exĂ©cuter des requĂȘtes authentifiĂ©es contre votre API.

Btw, juste parce que vous mettez le JWT dans un cookie (par exemple, savoir si l'utilisateur est connectĂ©), ne signifie pas que vous ĂȘtes empĂȘchĂ© d'utiliser la valeur du cookie (par exemple un JWT) pour le serveur inter-domaine Ă - AccĂšs au serveur API au chargement de la page (qui fonctionne Ă©galement pour le scĂ©nario de proxy inverse). Vous n'ĂȘtes pas non plus empĂȘchĂ© de transmettre le JWT Ă  l'Ă©tat initial Ă©galement pour les requĂȘtes navigateur-serveur API. Ils ne s'excluent pas mutuellement.

En passant, je trouve l'idée de JWT « sans état » à la fois surestimée et limitée dans son application pour la majorité des cas d'utilisation. Par exemple:

  • Autorisations basĂ©es sur les ressources / dynamiques (par exemple, pas seulement " can edit Post ", mais plutĂŽt " can edit Post:1634 ").
  • Que faire si le compte de l'utilisateur a Ă©tĂ© bloquĂ©/supprimĂ© ?
  • N'ont pas payĂ© leur abonnement mensuel ; quelle fonctionnalitĂ© d'accĂ©lĂ©rateur ?
  • Mettre le jeton sur liste noire (comme ci-dessus) ?

Vous n'intĂ©grez pas tout cela dans le JWT, ce qui signifie que vous devez puiser dans la couche de domaine (c'est-Ă -dire la base de donnĂ©es) pour le dĂ©couvrir. Vous venez de charger la ressource, alors autant la mettre lĂ  oĂč le reste de l'application peut y accĂ©der, et maintenant vous avez l'Ă©tat. Je trouve vraiment idiot de penser que tout ce que vous devez savoir sur le sujet serait intĂ©grĂ© au jeton; tout en le gardant principalement anonyme et lĂ©ger. Sans trop digresser, il y a un argument en faveur des demandes « sans Ă©tat » dans la communication inter-services, mais mĂȘme cela, je trouve peu pratique (du moins en ce qui concerne le concept d'intĂ©gration de ce que vous devez savoir sur le sujet dans le JWT).. .

Stratégies d'authentification Ooth disponibles entre-temps (nouveau en gras) :

  • Local (Nom d'utilisateur/email/mot de passe)
  • Facebook
  • Google
  • InvitĂ©
  • PatrĂ©on
  • Twitter
  • Authy (Twilio) - sans mot de passe par SMS

@jaredpalmer vous avez Ă©crit
Comme php, l'unitĂ© atomique de Next est la page. L'une des fonctionnalitĂ©s les plus intĂ©ressantes est qu'il charge paresseux chaque page uniquement lorsque cela est demandĂ©. Avec l'authentification cĂŽtĂ© client uniquement mais avec le rendu serveur, le js de cette page protĂ©gĂ©e est en fait tĂ©lĂ©chargĂ© par le navigateur. À l'avenir, lorsque Next ajoutera des workflows de serveur, vous pourrez, espĂ©rons-le, bloquer le rendu et la redirection sur le serveur pour empĂȘcher cela complĂštement. Cela nĂ©cessitera des cookies, des sessions et des magasins de sessions AFAIK, mais ce n'est que le coĂ»t de crĂ©ation d'applications hybrides comme celles-ci.

Nous sommes 2 ans plus tard. Existe-t-il un workflow de serveur pour empĂȘcher le chargement de js pour les pages protĂ©gĂ©es ?
@timneutkens peut-il mettre du contenu protégé dans une autre zone ?
Comment empĂȘcher totalement l'accĂšs au contenu protĂ©gĂ© ?

@lishine Vous avez un ServerResponse dans le getInitialProps de votre page - vous pouvez facilement rediriger une personne non privilégiée.

Existe-t-il un exemple d'authentification avec redux ?

Existe-t-il un exemple d'authentification avec redux ?

Vous pouvez essayer cet exemple qui utilise redux, et vérifier si cela fonctionne pour vous...
Vous pouvez le trouver quelque part dans ce sujet, mais au cas oĂč vous ne le trouverez pas, le voici :
https://github.com/alan2207/nextjs-jwt-authentication

Je pense que c'est un problÚme plus compliqué lors de l'utilisation des résultats d'appel d'API cÎté serveur getInitialProps, car Virtual DOM utilise d'anciens résultats aprÚs l'action LOGOUT-LOGIN. je réfléchis à une solution

_ÉDITÉ_
et voici ma réponse avec redux-observable

|Side|Auth|TODO|
|---|---|---|
|Server|true|RĂ©cupĂ©rer les donnĂ©es initiales (avec le proxy de cookie de requĂȘte).|
|Server|false|Afficher la page de connexion et récupérer les données aprÚs la connexion.|
|Client|true|Récupérer les données initiales.|
|Client|false|Afficher la page de connexion et récupérer les données aprÚs la connexion. (Cela se produit uniquement lorsque la session a expiré lors du déplacement de page en page) |

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

Cela semble compliqué quand quelque chose de simple ferait l'affaire, du genre :

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} />;
    }
};

Cet exemple a été fusionné dans le cadre de Next.js 8
https://github.com/zeit/next.js/tree/canary/examples/with-cookie-auth

@timneutkens merci pour le lien.

en regardant https://github.com/zeit/next.js/blob/canary/examples/with-cookie-auth/www/utils/auth.js#L26 -L34 ... ne devrait-il pas y avoir une sorte de vérifier aprÚs que auth() été appelé ?

Tester l'exemple sans cookie conduit Ă  l'appel de Profile.getInitialProps() , alors que je pensais que la redirection se produirait avant mĂȘme d'essayer d'obtenir plus d'"accessoires initiaux" ...

J'ai fait un exemple ici qui a un pré-rendu cÎté serveur + authentification avec apollo

https://github.com/HorizonShadow/apollo-next-now-test

Veuillez garder Ă  l'esprit que les directives de sĂ©curitĂ© OWASP recommandent de ne pas stocker le jeton JWT dans le stockage local, c'est-Ă -dire "Un seul script intersite peut ĂȘtre utilisĂ© pour voler toutes les donnĂ©es de ces objets, donc encore une fois, il est recommandĂ© de ne pas stocker d'informations sensibles dans le stockage local."

Voici Auth0 : OĂč stocker les jetons et Tom Abbott : OĂč stocker vos JWT – Cookies vs stockage Web HTML5 .

Voici un exemple avec Nuxt.js + serveur proxy Express.js + backend Django. OĂč le serveur Express est utilisĂ© pour transmettre la demande d'authentification au serveur principal et gĂšre la protection CSRF lors de l'utilisation du stockage de jetons JWT dans un cookie (impose une restriction sur la longueur du jeton / la quantitĂ© d'informations pouvant ĂȘtre stockĂ©es dans le jeton JWT) : https :/ /github.com/danjac/nuxt-python-secure-example

@timneutkens J'ai besoin de documents sur la façon d'envoyer un jeton Ă  partir d'un cookie vers un middleware redux personnalisĂ© SSR. Je reçois les cookies dans _app.js . Mais comment dois-je le transmettre Ă  customApimiddleware. OĂč j'ai Ă©crit des demandes de rĂ©cupĂ©ration. Merci

J'ai Ă©crit un article Medium sur Next.js Authentication/User account.
C'est un tutoriel complet et mon braindump de prÚs de deux ans de développement et de réflexion pendant mon temps libre (mon premier commentaire sur ce problÚme date de février 2017).

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

Je pense que c'est l'un des meilleurs tutoriels pour gĂ©rer l'authentification dans une application nextj.js. J'ai vu des choses comme stocker des jetons dans localStorage (XSS), stocker des jetons dans des cookies (sans gĂ©rer CSRF) et mĂȘme stocker des jetons dans des cookies Ă  partir du navigateur (Ă  la fois XSS et CSRF vulnĂ©rables).

J'aime beaucoup votre solution avec le proxy inverse et le partage des informations de session entre diffĂ©rents services. J'aimerais vraiment ne pas crĂ©er de serveur personnalisĂ© pour l'application next.js, mais je pense que c'est le moyen le plus simple de gĂ©rer les sessions et d'empĂȘcher csrf (et peut-ĂȘtre d'ajouter le proxy inverse). Je peux mĂȘme finir par crĂ©er un projet monolithique (Ă  la fois pour le rendu de l'application et la gestion des opĂ©rations de base de donnĂ©es, etc.).

J'ai vu que certaines personnes (y compris ZEIT) gardent les API sans état et laissent l'application next.js gérer la session. Il transmet les jetons aux API. Mais aller avec des sessions ne fait que rendre les choses un peu plus serrées et moins compliquées.

Ce serait vraiment mieux d'avoir un exemple d'authentification complet pour next.js. Avec des choses comme l'authentification pour les API externes, le maintien de la session dans l'application next.js, le partage de session entre les services ou leur transmission de jetons, et peut-ĂȘtre mĂȘme l'actualisation des jetons s'ils ont expirĂ©. (Beaucoup de gens Ă©crivent beaucoup sur les JWT et les utilisent simplement dans leurs didacticiels, mais la plupart du temps, ils ne les font mĂȘme pas expirer ou ne les actualisent mĂȘme pas.)

Quoi qu'il en soit, vous avez Ă©crit l'un des tutoriels les plus complets sur ce sujet. Donc merci!

J'espĂšre vraiment qu'il y aura des exemples et une documentation beaucoup plus complets et clairs.

Ce serait vraiment mieux d'avoir un exemple d'authentification complet pour next.js. Avec des choses comme l'authentification pour les API externes, le maintien de la session dans l'application next.js, le partage de session entre les services ou leur transmission de jetons, et peut-ĂȘtre mĂȘme l'actualisation des jetons s'ils ont expirĂ©. (Beaucoup de gens Ă©crivent beaucoup sur les JWT et les utilisent simplement dans leurs didacticiels, mais la plupart du temps, ils ne les font mĂȘme pas expirer ou ne les actualisent mĂȘme pas.)

Moi aussi, je ne sais pas quelle approche choisir.
Merci beaucoup pour le lien vers l'article.
Actuellement, sur laquelle des implémentations avez-vous opté ?
Avez-vous trouvé un exemple d'autorisation complet pour la prochaine v9.3+ ?

Cela vaut la peine de vérifier la nouvelle approche basée sur les cookies d'Auth0
(Bien sĂ»r, c'est pour un fournisseur d'identitĂ© particulier, mais une approche pourrait ĂȘtre utile Ă  voir)
https://github.com/auth0/nextjs-auth0

  • Vraiment cool que vous puissiez "proxy" les requĂȘtes api via les routes api de nextjs (mĂȘme via une route dynamique)
  • Ensuite, vous n'avez jamais Ă  exposer les jetons d'accĂšs, etc.
  • Votre code cĂŽtĂ© client appellerait vos routes api nextjs, et les routes api effectueraient alors la vraie requĂȘte api

Gardez à l'esprit qu'ils disent que cette approche est "expérimentale" dans le ReadMe

Cela vaut la peine de vérifier la nouvelle approche basée sur les cookies d'Auth0
(Bien sĂ»r, c'est pour un fournisseur d'identitĂ© particulier, mais une approche pourrait ĂȘtre utile Ă  voir)
https://github.com/auth0/nextjs-auth0

  • Vraiment cool que vous puissiez "proxy" les requĂȘtes api via les routes api de nextjs (mĂȘme via une route dynamique)
  • Ensuite, vous n'avez jamais Ă  exposer les jetons d'accĂšs, etc.
  • Votre code cĂŽtĂ© client appellerait vos routes api nextjs, et les routes api effectueraient alors la vraie requĂȘte api

Gardez à l'esprit qu'ils disent que cette approche est "expérimentale" dans le ReadMe

Cet article est trÚs utile et couvre de nombreuses architectures différentes.
https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/

Utiliser les routes API en tant que proxy, se connecter / se déconnecter via les routes API, obtenir le jeton de l'API, le définir comme cookie HttpOnly est une approche solide, je pense.
Une prĂ©occupation peut ĂȘtre CSRF, mais vous pouvez facilement crĂ©er une solution avec le package csrf npm (pas csurf , mais cela pourrait aussi fonctionner).

@onderonur , merci pour l'article auth0.
c'est-à-dire qu'il existe actuellement un exemple fiable ou au moins minimal d'implémentation sur jwt pur avec next.js?
Je ne veux pas créer une couche avancée avec des cookies et les configurer. Dans l'application csr, nous avons simplement stocké le jeton dans localstorage et l'avons envoyé avec la demande.

@onderonur , merci pour l'article auth0.
c'est-à-dire qu'il existe actuellement un exemple fiable ou au moins minimal d'implémentation sur jwt pur avec next.js?
Je ne veux pas créer une couche avancée avec des cookies et les configurer. Dans l'application csr, nous avons simplement stocké le jeton dans localstorage et l'avons envoyé avec la demande.

J'ai utilisĂ© cette mĂ©thode pour l'un de mes dĂ©pĂŽts mais elle est toujours Ă  l'Ă©tat de brouillon, alors assurez-vous de les tester vous-mĂȘme :)
https://github.com/onderonur/post-gallery
En fait, la "couche de cookies" n'est pas une chose avancĂ©e. Appelez simplement le point de terminaison de connexion de votre API via la route API /api/login et si la requĂȘte aboutit, dĂ©finissez le jeton dans un cookie httpOnly .
Vous pouvez vĂ©rifier mon repo pour la mĂȘme implĂ©mentation exacte.

Une autre option est (si vous voulez avoir presque le mĂȘme flux que la configuration du jeton dans le stockage local), vous pouvez utiliser le package js-cookie npm, appeler votre point de terminaison de connexion avec une demande cĂŽtĂ© client, terminer s'il retourne un jeton, placez-le dans un cookie. Et lorsque vous faites une demande (via un intercepteur axios, etc.), lisez la valeur du cookie et transmettez-la Ă  votre API en tant qu'en-tĂȘte de demande. J'ai vu beaucoup d'applications (et mĂȘme certaines populaires) utilisant cette approche. Mais c'est un peu non sĂ©curisĂ©. Parce que vous ne pouvez pas dĂ©finir httpOnly cookies

Sachez qu'il s'agit d'un vieux fil (et d'un sujet de longue haleine en gĂ©nĂ©ral), mais pour ceux qui recherchent des rĂ©fĂ©rences ou des exemples supplĂ©mentaires, nous avons rĂ©cemment repris du travail sur NextAuth.js v2. Je ne le mentionne pas tant comme un plug - c'est un projet open source et un tas de gens l'ont aidĂ© - mais c'est super simple Ă  utiliser et le code et l'approche peuvent ĂȘtre utiles comme rĂ©fĂ©rence pour les gens.

Pour certains antécédents, comme NextAuth v1, il utilise des cookies signés, préfixés et HTTP uniquement, évitant ainsi les piÚges de sécurité courants liés à l'utilisation de jetons cÎté client.

NextAuth.js v2 prend en charge la connexion avec Apple, Google, Facebook, Twitter, GitHub, Auth0, Okta, Slack, Discord et d'autres fournisseurs OAuth (il prend en charge à la fois 1.x et 2.x). Vous pouvez l'utiliser avec MySQL, MariaDB, Postgres, MongoDB - ou aucune base de données (juste OAuth et JSON Web Tokens pour une solution 100 % sans serveur).

L'utilisation est trÚs simple, il existe une méthode statique universelle appelée session() et un crochet React appelé useSession() vous pouvez utiliser dans les composants cÎté client :

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>}
  </>
}

Il est conçu pour Next.js 9.x et Serverless, et n'a pas de dépendances comme Express ou PassportJS. Il inclut un fournisseur d'authentification que vous pouvez utiliser dans _app.js pour ajouter automatiquement l'état d'authentification à toutes les pages ; cela fonctionne à la fois pour le rendu cÎté client et cÎté serveur.

Pour plus d'informations, consultez next-auth.js.org ou consultez next-auth@beta sur NPM

C'est toujours un travail en cours - nous sommes toujours en train de peaufiner la documentation et le modÚle d'événement - avec une date de sortie cible ~début~ mi-juin.

Sachez qu'il s'agit d'un vieux fil (et d'un sujet de longue haleine en gĂ©nĂ©ral), mais pour ceux qui recherchent des rĂ©fĂ©rences ou des exemples supplĂ©mentaires, nous avons rĂ©cemment repris du travail sur NextAuth.js v2. Je ne le mentionne pas tant comme un plug - c'est un projet open source et un tas de gens l'ont aidĂ© - mais c'est super simple Ă  utiliser et le code et l'approche peuvent ĂȘtre utiles comme rĂ©fĂ©rence pour les gens.

Pour certains antécédents, comme NextAuth v1, il utilise des cookies signés, préfixés et HTTP uniquement, évitant ainsi les piÚges de sécurité courants liés à l'utilisation de jetons cÎté client.

NextAuth.js v2 prend en charge la connexion avec Apple, Google, Facebook, Twitter, GitHub, Auth0, Okta, Slack, Discord et d'autres fournisseurs OAuth (il prend en charge à la fois 1.x et 2.x). Vous pouvez l'utiliser avec MySQL, MariaDB, Postgres, MongoDB - ou aucune base de données (juste OAuth et JSON Web Tokens pour une solution 100 % sans serveur).

L'utilisation est trÚs simple, il existe une méthode statique universelle appelée session() et un crochet React appelé useSession() vous pouvez utiliser dans les composants cÎté client :

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>}
  </>
}

Il est conçu pour Next.js 9.x et Serverless, et n'a pas de dépendances comme Express ou PassportJS. Il inclut un fournisseur d'authentification que vous pouvez utiliser dans _app.js pour ajouter automatiquement l'état d'authentification à toutes les pages ; cela fonctionne à la fois pour le rendu cÎté client et cÎté serveur.

Pour plus d'informations, consultez next-auth.js.org ou consultez next-auth@beta sur NPM

C'est toujours un travail en cours - nous sommes toujours en train de peaufiner la documentation et le modÚle d'événement - avec une date de sortie cible ~début~ mi-juin.

Super travail ça !
Cela peut-il ĂȘtre utilisĂ© uniquement cĂŽtĂ© client ? Par exemple, j'ai une application API Rails - et j'utilise Next JS pour le cĂŽtĂ© client.

Cette page vous a été utile?
0 / 5 - 0 notes