Next.js: Login-/Authentifizierungsbeispiel hinzufügen

Erstellt am 29. Okt. 2016  ·  208Kommentare  ·  Quelle: vercel/next.js

Mit:

  • wiederverwendbarer Authentifizierungshelfer über Seiten hinweg
  • Sitzungssynchronisierung zwischen Registerkarten
  • einfaches passwortloses E-Mail-Backend, gehostet auf now.sh

Ich denke, das wird vielen Neulingen sehr helfen.

p0

Hilfreichster Kommentar

So habe ich auth, die schwimmend arbeitet. Wie an anderer Stelle erwähnt, ist es nur clientseitig, was letztendlich nur die halbe Miete ist.

"Ziemlich sicher"

Wie bei PHP ist die atomare Einheit von Next die Seite. Eine der coolsten Funktionen ist, dass jede Seite nur dann geladen wird, wenn sie angefordert wird. Bei nur clientseitiger Authentifizierung, aber beim Server-Rendering wird das js für diese geschützte Seite tatsächlich vom Browser heruntergeladen. Wenn Next in Zukunft Server-Workflows hinzufügt, können Sie hoffentlich das Rendern und die Umleitung auf dem Server blockieren, um dies vollständig zu verhindern. Dies erfordert Cookies, Sitzungen und AFAIK-Sitzungsspeicher, aber das sind nur die Kosten für solche Hybrid-Apps.

Auth-Beispiel

Angenommen, Sie haben eine JWT-gesicherte API mit zwei interessierenden Endpunkten: /token und /me . /token akzeptiert E-Mail-/Passwort-Anmeldeinformationen und gibt ein signiertes JWT ( id_token ) zurück, während /me Profilinformationen zum JWT-authentifizierten Benutzer zurückgibt. Ich habe das folgende AuthService.js aus der Sperre von Auth0 angepasst (Entfernen des Ereignissenders, obwohl das nicht die schlechteste Idee ist). Es extrahiert fast das gesamte JWT-Token-Handling, sodass es auf der Anmeldeseite und auch in einer Komponente höherer Ordnung verwendet werden kann (dazu später mehr).

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

Als nächstes folgt ein HOC, um den Schutz von Seiten zu vereinfachen. Um ein ungewolltes Aufblitzen sensibler Informationen zu verhindern, wird die Seite beim ersten Rendern Loading... server-rendern, während React hochfährt / das Token vom localStorage liest. Dies bedeutet, dass geschützte Seiten kein SEO werden, was derzeit wahrscheinlich in Ordnung, aber definitiv nicht optimal ist.

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

Die Login-Seite kann den HOC in seiner jetzigen Form nicht verwenden, da der Login öffentlich sein muss. Es erstellt also nur eine Instanz von AuthService direkt. Sie würden etwas Ähnliches auch für eine Anmeldeseite tun.

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

Inspiriert von Airbnbs Reaction-with-Styles begann ich auch mit der Arbeit an einer next-with-auth Bibliothek, die eine Funktion wäre, die einen HOC zurückgibt, der auf Seiten verwendet werden soll. Ich habe auch mit dem Zusammenführen von AuthService und diesem HOC gespielt. Eine Lösung könnte darin bestehen, dass dieser HOC zusätzlich zur Komponente eine Berechtigungsstufenfunktion als Argument akzeptiert, wie z. B. redux connect. Unabhängig davon würden Sie meiner Meinung nach next-with-auth wie folgt verwenden:

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

Das alles mit Redux zu machen schien unnötig kompliziert, aber im Grunde können Sie dem Wiki-Beispiel folgen, aber AuthService in Aktionen verschieben (An- und Abmelden) und einen User Reducer haben. Sie können diese Aktionen jedoch nur auf dem Client aufrufen, da auf dem Server kein localStorage vorhanden ist, sodass Sie dies in Ihren Aktionen überprüfen müssen. Letztendlich wird Redux Store sowieso auf die window gelegt. Sie können den Benutzer also einfach auf window anstatt den Kontext zu verwenden. Wenn Sie kein Redux wollen, können Sie auch react-broadcast ausprobieren.

Schließlich wird angenommen, dass next/server gemäß #25 versendet. next-with-auth könnte komplizierte LocalStorage- vs. Cookie-Zeug vom Entwickler mit Middleware + einem HOC abstrahieren. Es könnte auch die Token-Aktualisierung verarbeiten.

Alle 208 Kommentare

Vorschlag: Verwenden Sie Redux und JWT, um das Beispiel auszuführen

Ich arbeite an einem Beispiel dafür. Habe derzeit Probleme damit, dass componentWillReceiveProps auf meiner High-Level-Komponente ausgelöst wird (wobei ich vorhabe zu überprüfen, ob der Benutzer authentifiziert ist und andernfalls auf die Anmeldeseite umleiten)

So habe ich auth, die schwimmend arbeitet. Wie an anderer Stelle erwähnt, ist es nur clientseitig, was letztendlich nur die halbe Miete ist.

"Ziemlich sicher"

Wie bei PHP ist die atomare Einheit von Next die Seite. Eine der coolsten Funktionen ist, dass jede Seite nur dann geladen wird, wenn sie angefordert wird. Bei nur clientseitiger Authentifizierung, aber beim Server-Rendering wird das js für diese geschützte Seite tatsächlich vom Browser heruntergeladen. Wenn Next in Zukunft Server-Workflows hinzufügt, können Sie hoffentlich das Rendern und die Umleitung auf dem Server blockieren, um dies vollständig zu verhindern. Dies erfordert Cookies, Sitzungen und AFAIK-Sitzungsspeicher, aber das sind nur die Kosten für solche Hybrid-Apps.

Auth-Beispiel

Angenommen, Sie haben eine JWT-gesicherte API mit zwei interessierenden Endpunkten: /token und /me . /token akzeptiert E-Mail-/Passwort-Anmeldeinformationen und gibt ein signiertes JWT ( id_token ) zurück, während /me Profilinformationen zum JWT-authentifizierten Benutzer zurückgibt. Ich habe das folgende AuthService.js aus der Sperre von Auth0 angepasst (Entfernen des Ereignissenders, obwohl das nicht die schlechteste Idee ist). Es extrahiert fast das gesamte JWT-Token-Handling, sodass es auf der Anmeldeseite und auch in einer Komponente höherer Ordnung verwendet werden kann (dazu später mehr).

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

Als nächstes folgt ein HOC, um den Schutz von Seiten zu vereinfachen. Um ein ungewolltes Aufblitzen sensibler Informationen zu verhindern, wird die Seite beim ersten Rendern Loading... server-rendern, während React hochfährt / das Token vom localStorage liest. Dies bedeutet, dass geschützte Seiten kein SEO werden, was derzeit wahrscheinlich in Ordnung, aber definitiv nicht optimal ist.

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

Die Login-Seite kann den HOC in seiner jetzigen Form nicht verwenden, da der Login öffentlich sein muss. Es erstellt also nur eine Instanz von AuthService direkt. Sie würden etwas Ähnliches auch für eine Anmeldeseite tun.

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

Inspiriert von Airbnbs Reaction-with-Styles begann ich auch mit der Arbeit an einer next-with-auth Bibliothek, die eine Funktion wäre, die einen HOC zurückgibt, der auf Seiten verwendet werden soll. Ich habe auch mit dem Zusammenführen von AuthService und diesem HOC gespielt. Eine Lösung könnte darin bestehen, dass dieser HOC zusätzlich zur Komponente eine Berechtigungsstufenfunktion als Argument akzeptiert, wie z. B. redux connect. Unabhängig davon würden Sie meiner Meinung nach next-with-auth wie folgt verwenden:

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

Das alles mit Redux zu machen schien unnötig kompliziert, aber im Grunde können Sie dem Wiki-Beispiel folgen, aber AuthService in Aktionen verschieben (An- und Abmelden) und einen User Reducer haben. Sie können diese Aktionen jedoch nur auf dem Client aufrufen, da auf dem Server kein localStorage vorhanden ist, sodass Sie dies in Ihren Aktionen überprüfen müssen. Letztendlich wird Redux Store sowieso auf die window gelegt. Sie können den Benutzer also einfach auf window anstatt den Kontext zu verwenden. Wenn Sie kein Redux wollen, können Sie auch react-broadcast ausprobieren.

Schließlich wird angenommen, dass next/server gemäß #25 versendet. next-with-auth könnte komplizierte LocalStorage- vs. Cookie-Zeug vom Entwickler mit Middleware + einem HOC abstrahieren. Es könnte auch die Token-Aktualisierung verarbeiten.

Aufgeregt, das auszuprobieren! Danke für die Barebones-Implementierung :)

@jaredpalmer Ich arbeite an etwas Ähnlichem. Wie funktioniert Ihr AuthService , wenn eine Komponente serverseitig gerendert wird? Der Server benötigt Zugriff auf das JWT, kann es jedoch nicht aus dem lokalen Speicher lesen.

@amccloud Das tut es nicht. Das ist das ganze Problem. Der HOC rendert <div>Loading..</div> auf geschützten Routen und muss den Token lesen und entscheiden, ob in componentDidMount umgeleitet werden soll oder nicht. Damit es wie gewünscht funktioniert und serverseitig gerendert wird, benötigt Next #25 oder zumindest die Möglichkeit, ein Cookie mit dem Wert von JWT AFAIK zu setzen.

Ich habe cookie-js verwendet, um ein Cookie zu setzen, aber es ist ein bisschen ein Hack..
Die Sache ist: Wenn Sie kein Cookie senden, verlieren Sie alle Vorteile von nextjs und serverseitigem Rendering in authentifizierten Routen

@jaredpalmer das ist großartig! Danke für die Bemühung. Ich werde versuchen, Ihr Beispiel in den nächsten Tagen fertig zu implementieren (oder Ihnen dabei zu helfen, wenn Sie möchten)

Jo! Ein Beispiel mit nextjs und auth0 habe ich hier veröffentlicht: https://github.com/luisrudge/next.js-auth0
Es hat das Konzept eines Hauptlayouts und auch "sicherer Seiten", die nur geladen werden, wenn der Benutzer authentifiziert ist.
Lass mich wissen was du denkst

@luisrudge unglaublich. Ich klone und nehme einige Änderungen vor, aber sieht toll aus

Cool! Was denkst du, was fehlt? An welche Veränderungen denken Sie?

Am Sonntag, den 6. November 2016 um 13:12 -0200 schrieb "Dan Zajdband" < [email protected] [email protected] >:

@luisrudgehttps ://github.com/luisrudge erstaunlich. Ich klone und nehme einige Änderungen vor, aber sieht toll aus

Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf Gi tHub anhttps://github.com/zeit/next.js/issues/153#issuecomment -258687108, oder schalten Sie das AA5cE8NIsvQ_ITjc1gArTFgNXzEda4TSks5q7e5NgaJpZM4KkJmi.

1) Verwenden von standard für Linting (damit es mit allem übereinstimmt, mit dem wir als nächstes bauen)
2) Hinzufügen von Multi-Tab-Unterstützung angefordert von @rauchg
3) Der CSS-Teil kann vereinfacht werden

ich schicke dir eine pr :)

Was meinst du mit Multi-Tab-Unterstützung?

Am Sonntag, den 6. November 2016 um 13:16 -0200 schrieb "Dan Zajdband" < [email protected] [email protected] >:

1) Standard für Linting verwenden (damit es mit allem übereinstimmt, mit dem wir als nächstes bauen)
2) Hinzufügen von Multi-Tab-Support angefordert von @rauchghttps ://github.com/rauchg
3) Der CSS-Teil kann vereinfacht werden

ich schicke dir eine pr :)

Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie auf diese E - Mail direkt, sehen sie auf Gi tHubhttps: //github.com/zeit/next.js/issues/153#issuecomment -258.687.373 oder stumm schalten die th readhttps: //github.com/notifications/unsubscribe-auth/ AA5cE1A6jq4KZc9_ynukTCI4mU-rdsNaks5q7e81gaJpZM4KkJmi.

Sie haben 2 offene Tabs, logout auf 1, loggt sich automatisch auf dem anderen aus

Ahh. Das ist supercool!

Am Sonntag, den 6. November 2016 um 13:21 -0200 schrieb "Dan Zajdband" < [email protected] [email protected] >:

Sie haben 2 offene Tabs, logout auf 1, loggt sich automatisch auf den anderen aus

Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie auf diese E - Mail direkt, sehen sie auf Gi tHubhttps: //github.com/zeit/next.js/issues/153#issuecomment -258.687.707 oder stumm schalten die th readhttps: //github.com/notifications/unsubscribe-auth/ AA5cE9e2DA4_GgNQIVTMp0hx74G-6RmUks5q7fBfgaJpZM4KkJmi.

Hallo @luisrudge ich habe dir eine PR mit den Änderungen geschickt https://github.com/luisrudge/next.js-auth0/pull/2

vielen Dank dafür <3

Das ist übrigens das Ergebnis:

2016-11-06 11 14 31

@impronunciable @luisrudge Fantastische Umsetzung! Wenn Sie es ohne Auth0 verwenden möchten, müssen Sie anscheinend nur die Dateien im Verzeichnis ./utils ändern, vielleicht sogar nur lock.js . Ich werde das demnächst ausprobieren. Übrigens sieht das Multi-Tab super aus

@ugiacoman Ich habe mit der Implementierung eines kleinen Servers mit passwordless.net begonnen, lass es mich wissen, wenn du meinen Code als Ausgangspunkt haben möchtest

@impronunciable Das wäre toll! Eigentlich wollte ich etwas Ähnliches mit den Digits von Twitter Fabric machen.

@improuncible Ich schlage vor, das Passwort less.net nicht zu verwenden, stattdessen können Sie einfach Passport-Local verwenden und den Benutzern einfach einen Link mit ihrer E-Mail und ihrem Token in der Abfragezeichenfolge senden.

Danke @impronunciable ❤️

@ugiacoman ja, es ist ziemlich einfach, die auth0-Abhängigkeit zu entfernen. Ich habe es verwendet, weil ich keine separate API für die Authentifizierung haben wollte

@jaredpalmer Soweit ich weiß, wäre # 25 großartig, aber blockiert es nicht? Ich meine, wir haben Zugriff auf das serverseitige req in getInitialProps also hindert nichts daran, cookie-parser darauf anzuwenden? Serverseitiges Authentifizierungs- und Sitzungsmanagement ist für mich alles neu

Übrigens, wenn man bedenkt, dass localStorage nicht serverseitig verwendet werden kann, sind Cookies die einzige Möglichkeit, serverseitige Sitzungen durchzuführen? Ich habe eine vage Erinnerung, es ist vielleicht nicht die sicherste? Aber gibt es noch eine andere Möglichkeit?

@sedubois

Der Cookie-Ansatz kann sehr sicher sein, wenn er richtig durchgeführt wird. Folgendes zu tun ist ziemlich trivial:

  • Verwenden Sie das httpOnly-Flag (verhindert den JavaScript-Zugriff auf das Cookie)
  • sicheres Flag verwenden (nur Cookie für https-Anfragen setzen)
  • Signierte Cookies (Quelle des Cookies überprüfen)

Es gibt auch einen sehr erheblichen Latenzvorteil, wenn Sie direkt auf dem Server auf Authentifizierungsinformationen zugreifen können.

Wir sollten dieses Beispiel in examples/ Ich werde sehen, was mir einfällt

Ich habe es geschafft, react-cookie für isomorphe Cookies zu verwenden, indem ich nextjs wie folgt in einen benutzerdefinierten Express-Server einpacke:

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

Dies ermöglicht es mir, eine authentifizierte Anfrage von der Serverseite aus zu stellen. Dies behebt keines der Probleme der ursprünglichen Aufzählungszeichen, sondern löste das Problem der Freigabe des Status zwischen Client und Server.

Aus dem POV von jemandem, der viel von diesem Zeug lernt. Ich denke, es wäre am besten, wenn sich die Beispiele nicht auf Dienste von Drittanbietern wie auth0 verlassen. Für Neulinge wäre es vorteilhafter, ein Barebone-Beispiel mit Anmelde-/Anmeldeformularen und der Verwendung von Redux und JWT zu sehen.

Das Beispiel, das wir _bundle_ planen, basiert auf Open-Source-Node.js-Server-APIs

Ich habe einem Beispiel-Starterprojekt unter https://github.com/iaincollins/nextjs-starter ein Beispiel für eine E-Mail-basierte Authentifizierung hinzugefügt

Es hat Sitzungsunterstützung (mit Express Sessions im Backend und der Browser-SessionStorage-API, um sie im Frontend zwischenzuspeichern), httpOnly Cookies, CSRF-Projektion, verwendet integriertes SMTP zum Senden von E-Mails, ein einfach zu änderndes Backend, das standardmäßig auf SQL Lite eingestellt ist . Es ist keine Konfiguration erforderlich, um es auszuführen.

Das Projekt hat auch Layoutseiten, benutzerdefinierte Routen und enthält das Uhrenbeispiel aus dem Wiki. Es ist nicht das schickste Beispiel für Authentifizierung, aber es könnte hilfreich sein für diejenigen, die einen einfachen Einstieg in ein einfaches Projekt suchen, das leicht zu verstehen und zu spielen ist.

Ich stimme @iamjacks zu, dass ein Beispiel mit JWT eine gute Idee zu sein scheint.

Ich freue mich, die Fehlerbehandlung zu verbessern und Funktionen wie eine einfache Profilseite hinzuzufügen, die Benutzer bearbeiten können, und Passport-Integration mit Beispielen für oAuth für Facebook, Google und Twitter, wenn dies für die Leute nützlich wäre. Wenn Leute gute Ideen für bessere Möglichkeiten haben, Sitzungsinformationen für Komponenten zu verbreiten / verfügbar zu machen, bin ich sehr daran interessiert.

Example screenshot showing what to expect

Das ist ziemlich unglaublich @iaincollins. Wir werden dies auf jeden Fall in den Versionshinweisen für 2.0 vorstellen :)

@rauchg Danke! :)

Ich denke, ich sollte explizit hinzufügen, dass in diesem Beispiel Sitzungen sowohl client- als auch serverbasiert sind - dh mit und ohne JavaScript arbeiten (und auf Systemen ohne sessionStorage), und dieselbe Sitzung wird von beiden geteilt.

Dies zu erreichen, wird in der Session-Komponente etwas kniffelig, die sich mit Variablen mit Namen wie req.connection._httpMessage.locals._csrf befasst, um das CSRF-Token aus den Serverheadern abzurufen - als das 'req'-Objekt, das in getInitialProps() an Seiten übergeben wird. ist seltsamerweise etwas anders als das in Express exponierte req-Objekt, da ich normalerweise über req.locals._csrf darauf zugreifen würde (jedoch ist req.session in beiden gleich).

localStorage ist nicht sicher. was ist der beste Weg, um es sicherer zu machen. jeder kann localStorage-Daten stehlen und wieder in seinen Browser laden und als Opferbenutzer protokolliert werden!!

@Chathula das stimmt nicht. Dieses Argument ist falsch.
Wenn jemand physisch Zugriff auf den Browser hat, kann er alles tun.

Das gilt auch für Kekse.

Die Verwendung von localStorage für die Authentifizierung ist ziemlich sicher, da wir Cookies-basierte Sicherheitsprobleme beseitigen könnten.
Aber auf der anderen Seite betrifft es SSR.

@arunoda Ich habe ein Login mit Laravel API und Next.js Client erstellt. Ich speichere authUser access_token in localStorage. Überprüfen Sie dann, ob der Benutzer angemeldet ist oder nicht, indem Sie sich authentifizieren. aber es ist nicht sicher. wenn jemand die localStorage-Daten gestohlen hat. er/sie kann es benutzen.

wenn jemand die localStorage-Daten gestohlen hat.

Wie? Grundsätzlich sollte er/sie physisch Zugriff auf den Browser haben. Dann könnte diese Person alles tun.
Darum sollten wir uns also keine Sorgen machen.

Können wir keine Verschlüsselung verwenden, um es viel sicherer zu machen?

@Chathula, das geht vom Thema ab. Es ist nicht gerade relevant für Next.js und wir wollen uns daran orientieren, wie Web-Sachen normalerweise funktionieren.

@Chathula vielleicht eröffnen .

@arunoda hahaha!! Danke für die Information! :D

@Chathula Ich bespreche es gerne in einer Ausgabe des Starterprojekts, wenn Sie spezielle Bedenken haben.

Ich möchte alle Missverständnisse korrigieren, um zu vermeiden, dass die Leute unnötig beunruhigt werden.

Die Web-Storage-API (dh localStorage und sessionStorage) ist - wie Cookies ohne gesetztes httpOnly - durch Same Origin Policy (Protokoll, Hostname, Portnummer) eingeschränkt, es stimmt nicht, dass "jeder [es] stehlen kann"; aber ja, wenn jemand in der Lage ist, über eine Cross-Site-Scripting-Sicherheitslücke in Ihrer Anwendung beliebiges JavaScript auf Ihrer Site auszuführen, dann kann er auch auf den Store zugreifen, daher sollten Sie keine Sitzungskennungen darin speichern.

Aus diesem Grund werden Sie sehen, dass das Sitzungstoken selbst nicht in localStorage/sessionStorage gespeichert und in JavaScript nicht lesbar ist, sondern nur über ein HTTP Only-Cookie übertragen wird (weshalb die Sitzungsklasse XMLHttpRequest() statt fetch() verwendet - wie in der Klassendokumentation erklärt).

Dies bedeutet, dass selbst wenn jemand in der Lage ist, eine Cross-Site-Scripting-Sicherheitslücke in Ihrer Anwendung auszunutzen und beliebiges JavaScript in Ihrer Web-App auszuführen, er dennoch kein Sitzungstoken eines Benutzers lesen oder exportieren kann.

Dies ist vielleicht eine wichtige Unterscheidung, die es wert ist, in der Dokumentation berücksichtigt zu werden.

Hinweis: Eine zusätzliche Verschlüsselung der Benutzerdaten ist hier nicht hilfreich, da die App immer in der Lage sein muss, die Daten zu lesen, damit sie gerendert werden können (Sie müssten also auch einen Beschreibungsschlüssel in der App speichern, der die Verschlüsselung wiedergeben würde Benutzerdaten ziemlich strittig).

_UPDATE: In den letzten ein oder zwei Wochen wurde das Beispiel überarbeitet, um localStorage über sessionStorage zu verwenden, da sessionStorage nicht zwischen Registerkarten geteilt wird und nicht sensible Daten auf diese Weise die Anzahl unnötiger Authentifizierungsprüfungen reduziert und den Sitzungsstatus zwischen den Registerkarten konsistent hält._

Vielleicht nützlich für einige Leute, die ich beim Experimentieren mit dieser Beispiel-App erstellt habe:

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

Unterstützt von diesem Spielzeug-Backend:

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

Hier eingesetzt:

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

Backend hier:

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

@Möglichkeiten Danke Mike! Ebenso wie die Bereitstellung eines separaten Microservices, der eine nette Art und Weise zeigt, sichere Seiten zu handhaben, von denen ich dachte, dass sie ein gutes Pragma sein könnten und von denen sie sich inspirieren lassen könnten. Ich habe einige Ideen, die im next.js-with-auth-Repository auftauchen werden.

Nach einigem Nachdenken würde ich meine Bemühungen wahrscheinlich nicht als großartiges Beispiel betrachten. Ich würde wahrscheinlich dazu wechseln, dass die Anmeldung/Anmeldung den Web 1.0-Stil vollständig übermittelt, damit wir auf dem Server ein reines HTTP-Cookie erstellen können (wodurch die Zugänglichkeit zum JWT über XSS beseitigt wird) und dann das Benutzerobjekt stattdessen an req anhängen können als das gesamte Token. Dies lässt die Möglichkeit von CSRF-Schwachstellen, aber ich denke, dies ist einfacher zu mindern als XSS (nein?). Ein schöner Nebeneffekt davon ist, dass die Client-App dann einen nahezu identischen Ablauf für die Anmeldung über einen Eid-Dienst verwenden kann.

Im Nachhinein sehe ich auch, dass ich die "Middleware" (und daher die Notwendigkeit eines benutzerdefinierten Servers) vermeiden konnte, indem ich das Cookie im Page HoCs getInitialProps parse.

@possibilities Da die 'geheime' Seite nur eine Seite ist und von Webpack gebündelt wird, würde sie nicht an den Browser geliefert, wenn ich zu /geheim gehe?

Ja, ich nehme an, das sollte verdrahtet sein, um eine serverseitige Umleitung durchzuführen.

Übrigens, ich wurde von meinem ursprünglichen Projekt abgelenkt, mich mit github anzumelden. Der Ablauf ist ähnlich, mit mehr Sorgfalt auf die Sicherheit (nämlich kein Geheimnis auf dem Client preiszugeben, um zu vermeiden, dass Oauth-Token über XSS offengelegt werden). Es ist in eine richtige App eingebunden, aber wenn es Interesse gibt, könnte ich es in etwas aufteilen, das für den Oauth-Flow im Allgemeinen nützlich sein könnte.

@possibilities Ich denke, es wäre eine großartige Hilfe, wenn es eine PR mit einem minimalen (aber ordentlichen) Beispiel mit Authentifizierung geben könnte 🙂 Ich arbeite an Authentifizierung in meiner App (https://github.com/relatenow/ beziehen), aber es ist derzeit nur clientseitig (localStorage).

@sedubois Ich habe einen https://github.com/zeit/next.js/pull/646, aber wir werden den Authentifizierungsserver woanders hin verschieben

wie wäre es mit graphql?

Apollo gibt ein Beispiel für die graphql-Authentifizierung:

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

Hier authentifizieren wir eine graphql-Anfrage, die jedoch für unseren Fall angepasst werden könnte.

Außerdem kann graphql Implementierung und Logik abstrahieren. Es könnte mit passwordless, auth0 oder allem anderen, was wir bevorzugen, verwendet werden.

@impronunciable FYI mit Ihrem Beispiel weiß ich noch nicht, wie ich mit Sitzungen @iaincollins in meiner App anzupassen.

Meine Anforderungen sind:

  • sicher
  • Authentifizierung auf der Serverseite, dann auf der Clientseite
  • unterstützt sowohl Facebook als auch Login/Passwort
  • Authentifizierungsanbieter sollten leicht geändert werden
  • Benutzer in Graphcool erstellen
  • nachfolgende GraphQL-Anfragen an Graphcool authentifizieren

Falls es jemandem hilft, hier ist meine App mit serverseitiger Authentifizierung 🙂

Die Authentifizierung sollte vom Next.js-Server getrennt werden, aber ich warte darauf, dass jemand anderes dazu Inspiration gibt ... Außerdem bin ich mir nicht sicher, ob sie richtig gegen CSRF geschützt ist.

Das habe ich gemacht:

  • Wenn sich der Benutzer anmeldet, setzt clientseitiges Javascript ein Cookie im Browser, das das Authentifizierungs-Trägertoken enthält
  • bei authentifizierten Anfragen liest der serverseitige Code (next.js) das Bearer-Token in den Headern der Anfrage des Browsers und verwendet es, um den API-Server im Auftrag des Clients zu kontaktieren

Dies ist anfällig für XSS- und CSRF-Angriffe (auch wenn Reaction viel dazu beiträgt, dies zu verhindern), aber es ist einfach und funktioniert mit SSR.

Nur um die Anfragen zu ergänzen

graph.cool + apollo + jwt + auth0 + next.js, die ersten 4 Teile davon sind bereits fertig auf https://github.com/graphcool-examples/react-apollo-auth0-example

@balupton Was passiert in Ihrem Beispiel, wenn das Token abläuft, während der Benutzer noch verbunden ist, ist die Sitzung gerade vorbei oder wird sie irgendwie erneuert?

@nmaro weiß nicht, nicht von mir geschrieben - am besten da drüben nachfragen

Für meine eigene App habe ich auth mit next.js und auth0, dann mit einem zeit/micro-API-Server, der die Bearer-Token überprüft.

Sollte irgendwann im Februar als Open Source verfügbar sein.

Nach der gleichen Philosophie, die next.js verfolgt hat (tun Sie eine Sache und machen Sie es gut), habe ich das Skelett eines erweiterbaren Benutzerkontensystems für Knoten entwickelt. Siehe die Philosophie hier: https://medium.com/the-ideal-system/ooth-user-accounts-for-node-js-93cfcd28ed1a#.97kyfg4xg

Das Github-Projekt ist hier: https://github.com/nmaro/ooth/

Das Ziel ist ein erweiterbarer, unabhängiger Authentifizierungs- und Benutzerverwaltungsdienst, der sich ideal für die Verwendung als separater Microservice eignet, eine Anwendungsstruktur, die sehr gut mit node.js harmonieren würde.

Ein Beispiel mit E-Mail+Passwort-Authentifizierung finden Sie hier: https://github.com/nmaro/ooth/tree/master/examples/ooth
Für Facebook und Google Auth gibt es bereits Pakete (ooth-facebook und ooth-google), die auf Basis von Passport-Facebook bzw. Passport-Google einfach zu implementieren sein sollen.

Ich werde so schnell wie möglich ein next.js-Integrationsbeispiel veröffentlichen. Beteiligen Sie sich gerne an der Diskussion und tragen Sie dazu bei.

Entschuldigung für den Stecker, aber es ist zum Wohle der Allgemeinheit - ich glaube wirklich, dass es noch keine gute Lösung für Node gibt, und dies ist genau das richtige Publikum von Leuten, die so etwas vielleicht wollen. Frieden

In der Zwischenzeit... hier ist ein Beispiel für eine graphql-API, die nur für Schreiboperationen eine Authentifizierung mit einem JWT-Token erfordert. Fühlen Sie sich frei, es mit Ihrer bevorzugten Authentifizierungsmethode zu verwenden :)

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

Ich habe https://nextjs-starter.now.sh aktualisiert, um oAuth-Unterstützung hinzuzufügen.

screen shot 2017-02-10 at 05 03 19

  • Es verwendet Passport für oAuth, zusammen mit Express-Sessions (wie zuvor).
  • Es gibt Unterstützung für Facebook, Google und Twitter+ oAuth und es ist einfach, weitere hinzuzufügen (siehe AUTHENTICATION.md und /auth-passport.js ).
  • Es verwendet das universelle Client/Server-Sitzungssystem (mit CSRF-Token, XSS-Schutz über HTTP Only-Cookies, die ORM-Schicht, die Mongo, SQL-DBs, Redshift usw. unterstützt) als E-Mail-Anmeldung.
  • Kann berichten, dass die Erfahrung mit der Konfiguration von oAuth auf Entwicklerportalen genauso schrecklich ist wie immer (seltsame Fehler passieren und es ist schwer zu debuggen).

Die Natur von oAuth - db + Sessions + Passport und Fehlerbehandlung müssen eng zusammenarbeiten - und von Sitzungen, die sowohl Client als auch Server funktionieren müssen und wie dies mit universellem Rendering funktioniert - bedeutet ein bisschen viel zu versuchen und auf einmal umzugehen, wenn Sie versuchen herauszufinden, was vor sich geht, aber die Clientlogik hat keine oAuth-spezifische Konfiguration, sodass sie nicht zu chaotisch ist.

Ich würde gerne nur die Authentifizierung in ein separates Beispiel aufteilen, obwohl ich vermute, dass es nicht viel kleiner wäre. Wenn jemand anderes möchte, super. Ich werde dem Beispiel wahrscheinlich irgendwann etwas mehr hinzufügen (wie eine Kontoverwaltungsseite). Wahrscheinlich wäre es gut, mehr auf die Dokumentation zu verlinken.

Erstaunliche Arbeit! Wenn Sie die Authentifizierung aufteilen und zum next.js-Repository hinzufügen könnten, wäre das großartig :heart:

Ich kann das übrigens auch

Ich werde in den nächsten 2 Wochen oder so keine Zeit haben, also wenn jemand möchte, wäre das großartig.

Ich würde es gerne umgestalten und sehen, ob es auf nur ein Modul reduziert werden könnte (das einfache Komponenten wie Anmeldeschaltflächen und Anmeldeformulare zum Einbetten bereitstellt) und mich von dem wirklich schönen früheren clientseitigen Beispiel inspirieren lassen von @impronunciable.

Update: Eigentlich gehe ich weg, weshalb ich nicht kann, aber wenn ich zurück bin, schaue ich mir das gerne an!

Ich habe die Kurzanleitung auth0/react mit einigen Änderungen befolgt, aber wenn ich lock.show() anrufe, beschweren sich die App-Beschwerden:

Nicht abgefangener Fehler: addComponentAsRefTo(...): Nur ein ReactOwner kann Refs haben. Möglicherweise fügen Sie einer Komponente eine Referenz hinzu, die nicht in der Methode render einer Komponente erstellt wurde, oder Sie haben mehrere Kopien von React geladen

@iaincollins @timneutkens bezüglich Ihres Beispiels, bitte korrigieren Sie mich, wenn ich falsch

Im Beispiel wird ein httpOnly-Cookie verwendet, um ein Sitzungstoken zu speichern, das es vor JavaScript-Injiection-Angriffen (XSS) sicher macht. Dann macht es sich die Mühe, ein csrf-Token im lokalen Speicher ablegen zu lassen, um auch vor CSRF-Angriffen zu schützen.

Es liegt die Annahme zugrunde, dass diese Kombination von Techniken die Dinge sicher macht, was den Benutzer/Entwickler in die Irre führen könnte. Ein Angreifer kann immer noch Javascript in die Seite (XSS) einschleusen, das csrf-Token lesen und es verwenden, um authentifizierte (Cookie-)Anfragen an die API auszuführen. Ist in der Readme erwähnenswert?

Hallo @davibe

Leider gibt es derzeit keinen technisch besseren Ansatz als einen Sitzungscookie und ein separates rotierendes CSRF-Token, also muss ich wohl sagen, dass ich mit dem Modell im Großen und Ganzen zufrieden bin, da es nicht wirklich eine andere Möglichkeit gibt (auch wenn die tatsächliche Umsetzung immer noch verbessert werden könnte).

Wir könnten Browser-Fingerdruck hinzufügen, vielleicht könnte das Session-Token häufiger rotieren (ich vergesse, ob das gerade automatisch ist), das CSRF-Token könnte ein Header anstelle von Param sein, die Cookies sollten wirklich nur SSL in der Produktion sein und wir könnten hinzufügen ein Ablaufdatum für die Anmelde-Token, aber AFAICS gibt es in Bezug auf das Sicherheitsmodell ziemlich begrenzten Spielraum für Verbesserungen und nichts, was wirklich weiteren Schutz bietet, falls jemand in der Lage ist, beliebigen Code in eine App einzuschleusen; aber bitte zögern Sie nicht, diese Dinge als Probleme für Verbesserungen im Repo anzusprechen.

Wenn es Optionen zum Ändern des Kontostatus gäbe (die es derzeit nicht gibt), könnten wir vor der Ausführung ein CAPTCHA verwenden, um Änderungen auf dem Server ohne Erlaubnis zu erschweren, aber im Beispiel können sich Benutzer nur anmelden und aus, so dass das derzeit außerhalb des Geltungsbereichs liegt.

Die lokale Speicherung von Sitzungstoken würde es deutlich weniger sicher machen und gegen die beabsichtigte Verwendung in der Spezifikation verstoßen, daher bin ich persönlich nicht dafür - obwohl ich es zu schätzen weiß, dass es die Dinge vereinfachen würde, da es keine CSRF-Projektion hat, aber die Leute wahrscheinlich Ich brauche kein Beispiel dafür, da es sehr einfach wäre - ich habe nur versucht, eines bereitzustellen, weil es so umständlich ist. :-)

Ich bin voll und ganz bei Ihnen, auch ich hasse es, wie notwendigerweise umständlich es ist, und habe den Versuch, es in ein Modul zu verwandeln, nicht aufgegeben.

Hmm.. ich verstehe.
Dieses Problem war für mich sehr hilfreich, danke.

Dies ist der Standpunkt von Auth0 https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
Sie schlagen grundsätzlich vor, Cookies zu vermeiden, aber das würde SSR beim ersten Laden der Seite auslassen, denke ich.

Hallo allerseits!

Ich arbeite auch an der Authentifizierung mit next.js und die Kommentare aus dieser Ausgabe, insbesondere @davibe + das Repo von @iaincollins und die PR von @timneutkens waren eine enorme Hilfe.

Meine Lösung macht folgendes:

  • Nach erfolgreicher Anmeldung speichert mein Redux Reducer den Token und die Benutzerdaten mit Hilfe von response-cookie in einem
  • Jede Seite/Komponente, die diese Informationen benötigt, wird in eine Komponente höherer Ordnung ähnlich wie @timneutkens with-session.js eingeschlossen . Wenn SSR, ist das Token in ctx.req.headers.cookie verfügbar, andernfalls nimm es einfach aus dem Browser-Dokument (verwende die React-Cookie-Lademethode).
  • Sobald ich das Token habe, kann ich es bei jeder Anfrage in den Kopfzeilen Bearer / Authorization setzen.

Es hilft, dass ich meinen eigenen JWT-Token-Authentifizierungs-Microservice in einem Docker-Container ausgeführt habe.
Vielleicht wäre es einfacher, einen einfachen JWT-Dienst als Teil des with-auth-Beispiels bereitzustellen? So vermeiden Sie, die server.js zu hacken und möglicherweise die Vorteile von next.js-integriertem Hot-Reloading, SSR und Routing zu verlieren?

Ich bin mir auch nicht sicher, ob dieser Ansatz in Bezug auf CSRF / XSS sicher ist. Alle Kommentare sind willkommen.

Danke an euch alle für die tolle Arbeit, die ihr bisher geleistet habt. Ich bin ein großer Fan von diesem Projekt!

@jcsmesquita Ich arbeite an einer neuen Version des Beispiels, bei der alles von Next.js getrennt ist, ähnlich wie die Authentifizierung bei zeit.co implementiert ist.

Dies scheint nützlich zu sein: https://hub.docker.com/r/rabbotio/nap/~/dockerfile/

@subsumo Danke für die Erwähnung, FYI: NAP gehört mir, die Authentifizierung über das Web basiert auf @iaincollins nextjs-starter und reagiert auf die native Client-Anmeldung mit Token.

@timneutkens ermöglicht Ihnen die Lösung, an der Sie arbeiten, die Authentifizierung bei einem separaten Dienst?

Ich habe mir den aktuellen Auth-Beispiel-Pull-Request https://github.com/zeit/next.js/pull/1141 angeschaut
Es scheint mir, dass es nur die Authentifizierung gegenüber dem next.js-Server ermöglicht, jedoch nicht isomorph gegenüber einem separaten Dienst.

Angenommen, Sie möchten den next.js-Server und die eigentliche App-API (zB REST oder GraphQL) trennen, dann möchten Sie, dass sich Client und Server gegenüber der API authentifizieren können. Ich glaube nicht, dass dir diese Lösung wirklich weiterhilft.

Ich dachte an eine Strömung.

Entitäten:

  • Kunde (C)
  • Next.js-Server (S)
  • API (A)

Ziel ist es, 3 Cookie-basierte Sitzungen einzurichten:

  1. CS
  2. CA
  3. SA

Sitzung 1) dient dazu, dass der Client den Server erkennt, und 2) 3) dienen dazu, dass sowohl der Client als auch der Server ihre jeweiligen Sitzungen verwenden können, um unabhängig auf die API zuzugreifen.

Das ist der Fluss:

  1. CS ist einfach, keine Authentifizierung erforderlich
  2. CA erfolgt mit Authentifizierung (zB mit Benutzername/Passwort). Zusätzlich wird ein JWT bereitgestellt
  3. Der Client stellt dem Server JWT zur Verfügung und verwirft es dann
  4. SA wird mit JWT durchgeführt, das dann verworfen wird

Was ist deine Meinung? Gibt es einen einfacheren Weg? Sollten wir stattdessen einfach die API mit dem next.js-Server gekoppelt halten, damit nur eine Sitzung (CS) benötigt wird?

@rauchg Ich

@timneutkens ermöglicht Ihnen die Lösung, an der Sie arbeiten, die Authentifizierung bei einem separaten Dienst?

Das ist die Idee, ja. War damit beschäftigt, andere Dinge auf Next.js zu reparieren. Werde so schnell wie möglich darauf zurückkommen.

Ich habe github-auth-spezifische Teile meiner App in ein ziemlich verdauliches Beispiel aufgeteilt. könnte für einige interessant sein und würde mich über Feedback zum Code oder Flow freuen :

UPDATE: Ich habe die Beispiel-App in einen wiederverwendbaren Satz von Komponenten umgestaltet, die in die nächsten Apps "hineingeworfen" werden können

Follow-up: Ich habe eine Integration mit Ooth und einer GraphQL-API geschrieben.

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

Es basiert auf bestehenden Ansätzen, dh Authentifizierung gegenüber dem next.js-Server, dh es wird davon ausgegangen, dass die API und der Authentifizierungsserver alle im selben Prozess laufen, sodass nur eine Sitzung erstellt werden muss. Der Vorteil: Es kann prinzipiell Credentials für / erweiterbar auf praktisch jede Passport.js-Strategie speichern.

@timneutkens irgendwelche Fortschritte an dieser Front?

Ich habe meine Github-Authentifizierungs-Beispiel-App in einen wiederverwendbaren Satz von Dekoratoren und Seitenkomponenten umgestaltet, um die nächsten Apps „github auth in“ abzulegen. Code- und Funktions-Feedback willkommen. https://github.com/possibilities/next-github-auth

Ich _glaube_, dass es interessant sein könnte, die Boards hier festzunageln und dies dann für die nächsten zu einem allgemeineren Auth-Framework weiterzuentwickeln.

@timneutkens
Entschuldigung, dass ich Sie anpinge, aber haben Sie diesbezüglich Fortschritte gemacht? Ich bin völlig verloren, wie ich die Authentifizierung mit next.js richtig einrichten soll.

@kolpav Ich habe etwas daran gearbeitet, derzeit überschwemmt mit anderem Zeug 😥 Das steht auf jeden Fall ziemlich weit oben auf meiner Prioritätenliste für Next 😄

Ein klarer, gut dokumentierter und sicherer Weg zur Authentifizierung mit einer next.js-App ist entscheidend für den Erfolg als Framework.

Ich kann mich nicht erinnern, wann ich das letzte Mal ein Web ohne Authentifizierung erstellt habe.
Wie die meisten Leute, die ich mir vorstelle, möchte ich auch gesicherte Anrufe an meine gesicherten Ruhedaten tätigen, daher scheint JWT die naheliegende Lösung zu sein.

Aber es gibt so viele Diskussionen zwischen den Themen und PR's, ich bin mir nicht sicher, wo ich anfangen soll!

@timneutkens
Cool 👍 Ich denke, es wird für andere sehr wertvoll sein.

@camstuart @kolpav Es gibt einige gute, funktionierende Beispiele oben, einschließlich der Unterstützung von oAuth und E-Mail-basierter Authentifizierung, die sowohl JWT- als auch HTTP-Cookies von den Mitwirkenden @jaredpalmer , @luisrudge , @impronunciable , @possibilities und mir verwendet.

Um einige Links hervorzuheben, funktioniert das Auschecken:

(Das Beispiel für die Mikroauthentifizierung war gut, aber ich denke, es muss aktualisiert werden.)

Es gibt Spielraum für weitere Verbesserungen, zu denen weitere Kommentatoren oben Stellung genommen haben – einschließlich einer Sitzungsspeicherkomponente und Aufteilung der Serverlogik; und ein Beispiel, das die Dinge, an denen Tim gearbeitet hat, noch weiter vereinfacht.

Einfachheit für die Authentifizierung ist ein schwieriges Gebiet für Universal-Apps, aber Sie sollten in der Lage sein, die obigen Beispiele zum Laufen zu bringen - oder einfach die Demos direkt auszuprobieren - und sehen, wie sie ohne allzu viel Aufhebens funktionieren.

@iaincollins Das sind tolle Beispiele. Aber wie kann ich (zum Beispiel) Starter-Projekt verwenden? Also wenn ich meine App bauen möchte. Ich muss dieses Repo klonen? Oder muss ich Code aus dem Starterprojekt Stück für Stück in meinen eigenen Code "kopieren und einfügen"?

Wenn das Starterprojekt aktualisiert wird - was soll ich tun?

@iaincollins
Schöne Beispiele, besonders deine.
Trotzdem würde ich gerne ein Auth-Beispiel mit zeit-Gütesiegel darauf sehen 😄 alle Augen würden in eine Richtung zeigen, damit Fehler oder Irrtümer nicht unbemerkt bleiben. Im Moment habe ich meine eigene Arbeitsberechtigung, bin mir aber nicht sicher, wie sicher sie ist.

Zugegeben @kolpav , Ihre eigene Sicherheit zu rollen ist eine knifflige Angelegenheit. Am besten den Experten überlassen

Ich habe dafür einen Stack erstellt, der die Authentifizierung mit GraphQL problemlos verarbeiten kann: https://github.com/thebillkidy/MERGE-Stack

@salmazov Ich habe einen nützlichen Weg gefunden, um zu beginnen und zu verstehen, was in einem Beispiel oder Starterprojekt vor sich geht, herausziehe , die nicht relevant sind, bis nur noch der Code für die Funktionalität übrig bleibt Sie implementieren möchten; und dann zu versuchen, genau diese Funktionalität auf ein anderes Projekt zu portieren.

@kolpav @camstuart Dieser Thread enthält eine wirklich ausführliche Diskussion verschiedener Sicherheitsmodelle, einschließlich der Entlarvung einiger häufiger Missverständnisse und Kompromisse. Ich möchte insbesondere die Punkte zu HTTP Only-Cookies und CSRF-Tokens beachten (und den zusätzlichen Schutz, den sie gegenüber XSS und CSRF gegenüber der Verwendung von JWT und/oder der Webspeicher-API für Sitzungstoken bieten). Es lohnt sich wirklich zu lesen.

@iaincollins Wolltest du etwas verlinken? :Lächeln:

Hallo Leute :)

Ich habe eine Frage, ich habe als nächstes gelesen, dass die Token für die Authentifizierung mit jwt nicht von localstorage abgerufen werden können.

Wenn ich einen Server zum Rendern rendern rendern im Glossar erklärt habe einfach die erste Ladung meiner Seite mit weiter. Und ich habe einen anderen Server für meine API. Diese erhalten den Benutzer/Pass vom Client und geben ein jwt. In welchen Fällen muss ich den Token in den Server bekommen??

Warum benötige ich Token im Renderserver (als nächstes)?

Wenn der Client das Token nicht an den API-Server sendet, gibt die API die Daten nicht weiter und der Benutzer kann keine privaten Informationen abrufen. Ich verstehe nicht, warum ich das Token an den Renderserver senden muss.

@kamilml

Dies könnte helfen. Im Allgemeinen haben Sie zwei Möglichkeiten:

  1. Next server JWT geben (evtl. per Cookie). Dadurch kann der Next-Server im Auftrag des Clients API-Aufrufe tätigen. Sie möchten dies, wenn Ihnen das vollständige serverseitige Rendering wichtig ist.

  2. Speichern Sie JWT im lokalen Speicher des Clients und geben Sie dem Next-Server keinen Zugriff darauf. In diesem Fall können Sie einfach die serverseitigen API-Aufrufe umgehen und das vollständige Rendern verschieben, bis das Laden der Clientseite abgeschlossen ist.

Entschuldigung für die Wiedereröffnung, aber ich dachte, ich würde meine 2 Cent zu diesem Thread hinzufügen und wie sich meine anfängliche F&E in diesem Bereich entwickelt. Weniger Codebeispiele, mehr High-Level-Flow.

Erstens ist der Großteil unserer App bereits in Symfony 3 (PHP) integriert und verwendet Vue für ein hybrides Erlebnis. Der Server rendert eine Wrapper-Seite und weist __INITIAL_STATE__ App-Daten zu, damit die App sie abholen kann. Dies führte zu einer Entscheidung zwischen dem Rendern von Marketingseiten in Symfony (für SEO) und der Wahl von UX/UI gegenüber SEO in anderen Bereichen, indem Daten über JS abgerufen und ein SPA-ähnliches Gefühl vermittelt wird. Erwähnenswert ist auch, dass nicht alle Seiten binär öffentlich/privat sind (wie ich in einigen Beispielen gesehen habe). Einige Seiten sind standardmäßig öffentlich und werden bei Authentifizierung anders gerendert. Wir erwogen, für Teile der Site ein SPA zu verwenden, aber in vielerlei Hinsicht war es eine schlechtere UX/UI (langsameres TTI, Fortschrittsbalken usw.). Außerdem löst das das SEO-Problem nicht, es sei denn, wir führen FOUC ein und rendern Text zweimal (einmal über Symfony, noch einmal als JS-Komponenten) usw.

Geben Sie SSR / Universal-JS ein...

In meinem Fall habe ich die PHPSESSID Logik nachgeahmt, indem ich ein HttpOnly UJSSESSID Cookie erstellt habe (den Namen erfunden) und den Wert auf den des Benutzers gesetzt habe JWT. Die Symfony-App gibt dies bei jeder Seitenanfrage weiter, während der Benutzer auf der Site navigiert. Wenn der Benutzer die UJS-Seiten aufruft, erhält die Serverseite dieser Apps die Cookies in der Anfrage (gemäß dem eingebauten Verhalten des Browsers). Wenn das UJSSESSID Cookie gesetzt ist, ruft die App die API auf, um die Benutzerinformationen abzurufen (z. B. /api/v1/users/me mit Übergabe des Tokens über den Authentication Header). Der Rest der Aufrufe erfolgt über die API unter Verwendung desselben Tokens. Der Symfony-Logout-Mechanismus löscht das UJSSESSID Cookie. Wenn die UJS-App das nächste Mal geladen wird, rendert sie die Seiten im anonymen Benutzermodus. Zu Ihrer Information, das Routing von Symfony- und UJS-Seiten erfolgt über Apache ProxyPass . LocalStorage wird nicht verwendet.

Das Endergebnis ist eine nahtlose UX, bei der sich der Benutzer auf einigen PHP-Seiten mit clientseitigem JS und auf einigen UJS-Seiten befindet. Dies ermöglicht uns, A/B-Tests durchzuführen und die Site iterativ zu aktualisieren – nicht jeder kann bei Null anfangen :)

Während dies aufgrund der symbiotischen PHP/UJS etwas komplizierter ist, kann das gleiche Prinzip in einer vollständigen UJS-Lösung mit einer API- oder Node.js-Server-Middleware (z. B. Express, Adonis usw.) verwendet werden. Anstatt das UJSSESSID Cookie über eine PHP-Seitenanforderung ( HttpOnly Flag) zu setzen, lassen Sie den Benutzer sich über Ihr SPA/UJS anmelden und setzen das Cookie dort. Was Sie NICHT tun sollten, ist Ihre App zu verwenden, um das JWT zu entschlüsseln oder Anrufe von Drittanbietern zu tätigen, für die ein client_secret erforderlich ist. Verwenden Sie dazu eine Middleware, die auf dem Server verbleibt.

Hoffe das hilft jemandem. Andere Beispiele, die ich gesehen habe, waren mir ein wenig zu Petrischale.

@jaredpalmer Hey, danke für diese Implementierung, ich habe es versucht, habe einfach deinen gesamten Code kopiert und deine Dashboard.js durch meine index.js ersetzt, die wie folgt aussieht:

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

export default withAuth(index)

und in withAuth hoc habe ich es geändert, um auf die Anmeldeseite umzuleiten.
Aber bevor es auf die Anmeldeseite umleitet, blinkt der Inhalt der Indexseite noch ein wenig. :S

Wie ist der Status dieses Problems? 😇

Das ist etwas überwältigend für neue Leute, die sich die ganze Diskussion durchlesen. Ich habe mich entschieden, die sehr einfache Authentifizierung hier zu implementieren. Nur 2 Seiten (Index, Login) und ein benutzerdefinierter Server
https://github.com/trandainhan/next.js-example-authentication-with-jwt

Grundsätzlich haben wir eine Authentifizierungs-Middleware im Server, um das Token im Header jeder Anfrage zu überprüfen. Der jwt-Token wird in Cookies gespeichert. Ich finde das ist sehr einfach, geradlinig und funktioniert sehr gut.

@trandainhan Könnten Sie einen POST-Endpunkt hinzufügen, der ein geheimes Token verwendet, um CSRF-Angriffe zu verhindern?

@sbking Aktualisierter Quellcode mit einem Beispiel-Endpunkt, der durch CSRF-Angriffe geschützt ist

Ist das einsatzbereit 😬?

Hat jemand Authentifizierung mit redux-auth-wrapper versucht?

Hallo zusammen! In den letzten Monaten habe ich erstellt und jetzt verfeinert

Es verfügt über:

  • Registrierung mit E-Mail und Passwort
  • Login mit E-Mail oder Benutzername und Passwort
  • Kontoseite, auf der Sie Ihren Benutzernamen festlegen, Ihr Passwort ändern und eine Bestätigungs-E-Mail erneut senden können
  • Passwort vergessen/Passwort zurücksetzen Seiten
  • E-Mail-Seite bestätigen
  • Eine grundlegende GraphQL-API, die mit einer MongoDB verknüpft ist (1 Datei, kann leicht entfernt werden)
  • Minimaler Boilerplate (so viel Logik wie möglich ist in Bibliotheken gekapselt)

Sehen Sie sich hier eine Live-Demo an: http://staart.nmr.io/

Ich habe es hauptsächlich für mich für Rapid Prototyping gemacht, um schnell mit einer Anwendung mit einem einfachen, funktionierenden Kontensystem zu beginnen, das nicht auf externe Dienste angewiesen ist. Ich bin mit den Ergebnissen recht zufrieden. Ich beabsichtige, diese Bibliotheken weiterhin zu verwenden und zu warten, also probieren Sie es aus, wenn Sie der Meinung sind, dass ein etabliertes Kontensystem + eine Benutzeroberfläche für den Knoten noch fehlt.

@trandainhan Danke, das ist ein wirklich großartiges Beispiel und für viele Leute viel einfacher und würde in vielen Szenarien funktionieren.

Ich werde mir überlegen, ob / wie ich die aktuelle Logik in nextjs-starter anpassen kann, um stattdessen so etwas sicher zu verwenden, während ich immer noch mit der Express-Sitzungslogik für reale Anwendungsfälle kompatibel bin (wie die Verwendung von Dinge wie Google oAuth APIs, bei denen ich den Server benötige, um die bei der ersten Anmeldung gewährten Token aufzubewahren und zu verfolgen).

Ich habe noch nicht herausgefunden, ob das möglich ist, aber es wäre für die Leute viel einfacher, wenn es so wäre.

Wenn nicht, ist es zumindest einen netten Beitrag wert, um den Leuten die verschiedenen Optionen zu erklären.

@trandainhan : Wenn ich <Link href="/">Home</Link> in login.js hinzufüge und dann auf den generierten Link klicke, kann ich auf die index.js zugreifen, ohne eingeloggt zu sein. Wie würden Sie vorschlagen, dies in Ihrem Beispiel zu beheben?

@iaincollins Ich sehe die meisten Lösungen hier, die sich gegen einen Oauth-Dienst authentifizieren. Gibt es eine gute Lösung für die Authentifizierung bei einer API, die auf JWT basiert?

@paulwehner Ich denke, das passiert, weil @trandainhan nur das serverseitige

@carlos-peru Unter der Haube verwendet Link tatsächlich next/router, um einen neuen Pfad in den Browserverlauf zu schieben. Scheint, als ob die meisten Dinge vom Browser gehandhabt werden, hier gibt es nichts für eine Middleware auf der Serverseite zu tun. Bisher kann ich nur daran denken, eine eigene Link-Komponente zu erstellen und andere Dinge zu tun, wenn wir die URL ändern.

@carlos-peru Sie können jederzeit einen benutzerdefinierten Server verwenden, um die volle Kontrolle über das Routing zu haben.

Danke @trandainhan und @kolpav! Ich muss ein besseres Verständnis haben, nachdem ich einige Zeit über das Wochenende verbracht habe. Es ist mir auch gelungen, eine Lösung zu implementieren, die auf HOC basiert und das jwt-Token auf einem Cookie hält, sodass sowohl der Server als auch der Client die API nutzen können.

@nmaro Ich habe ein Backend mit JWT-Authentifizierung für eine Website in next.js und eine App (react-native).

So. Ich denke im nächsten Modell: Der Client erhält einen Facebook-Token (Der Benutzer akzeptiert das Facebook-Login) und dann sendet der Client den Token an das Backend, um den Benutzer-Token zu überprüfen und zu validieren (passport-facebook-token im Node-js-Backend) . Wenn das Token in Ordnung ist, sendet das Back-End dann das im Back-End generierte JWT an den Client.

Das Problem? Ihr Tool kann den Schlüssel von Facebook und Google beziehen? Ich verwende hello.js, ist aber nicht mit next.js kompatibel und die ganze Welt verwendet Pass-Facebook. Ich denke, es ist ein großer Fehler, da der API-Server mit dem Webclient und der mobilen App kompatibel sein muss.

Dankeschön

PS: Ich kann in deinem Slack-Channel keine Einladung erhalten.

@hmontes hier - eine Einladung zum Slack-Channel für das ooth- Projekt (Benutzerkonten für Node, insbesondere next.js) gerne mitmachen. Ooth verwendet Passport-Facebook-Token (nicht Passport-Facebook) und Passport-Google-ID-Token, die meiner Meinung nach Ihr Problem lösen.

@nmaro Ich möchte dir bei deinem Projekt helfen. Ich habe auch ein Backend mit Graphql mit Passport-Facebok und Passport-Google-ID-Token !!!

Aber. Kennen Sie ein kompatibles Paket zum Verbinden des Facebook/Google-Clients in next.js?

Auf der Client-Seite könntest du ein ähnliches Muster verwenden, wie ich es hier verwendet habe: 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
(anstelle von oothClient.authenticate senden Sie einfach eine Post-Anfrage an Ihre Authentifizierungsroute).

@timneutkens wäre eine PR mit einem minimalen With-Ooth-Beispiel willkommen?

@nmaro in Ihrem Beispiel. Warum verwenden Sie componentDidMount anstelle von componentWillMount?

Ich erstelle eine HoC-Komponente (Anbieter) für die Google-Anmeldung.

Wird ComponentWillMount nur auf dem Client aufgerufen? Dann sollte es gut sein.

Okay. Vielen Dank für Ihre Beispiele. Endlich kann ich Auth mit Social Media implementieren.

Letzte Frage. Ich habe ein access_token und ein refresh_token erstellt und möchte localStorage einfügen, um die Daten zu speichern.

Wo kann ich das in next.js einfügen, um die Anmeldung beim Aktualisieren der Seite zu überprüfen? In create-react-app habe ich das in index.js eingefügt

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

Dankeschön

Bei ooth speichere ich die Facebook-Token nicht, ich verwende sie nur einmal mit Passport und erstelle dann eine normale Cookie-basierte Benutzersitzung.

Ah. Okay. Ich verwende JWT anstelle von Sitzungen. Also sende ich access_token an das Backend, es prüft, ob das Token im Dienst gültig ist (google, facebook), dann ob der Benutzer in meiner App existiert und schicke mir ein JWT zurück.

Dankeschön :)

Ich sollte hinzufügen, dass es gefährlich ist, JWTs in localstorage zu speichern (wegen XSS), besser als Cookies zu senden, wenn sich alles auf einem Server / einer Domäne befindet, damit der JavaScript-Code des Clients das JWT nicht abrufen kann, aber der Browser sendet die JWT automatisch als Cookies. JWTs sind knifflig (siehe lange Diskussionen oben), deshalb verwende ich in Ooth Sessions.

Ich verwende ein JWT nur, wenn ooth als externer Authentifizierungs-Microservice verwendet wird (da Cookies nur auf derselben Domäne funktionieren), und selbst dann verwende ich es genau einmal, um dann eine Sitzung mit dem Server zu erstellen, also wird es nirgendwo auf dem Client gespeichert .

Um die JWT-Sicherheit zu erhöhen, können Sie ein Aktualisierungstoken (von oauth2 entnommen) verwenden.

Kann eine mobile App mit Cookies umgehen?

@nmaro Okey. Ich verstehe dich. Entschuldigung für meinen Fehler.

Haben Sie ein Tutorial oder einen Code, um das JWT-Token in einem Cookie zu speichern? Ich suche https://github.com/zeit/next.js/blob/master/examples/with-firebase-authentication (Mein Authentifizierungssystem ist mit graphql)

Nein, tut mir leid, das habe ich nie gemacht.

@hmontes @nmaro
Ich habe das für mich selbst geschrieben, kann aber helfen:
https://github.com/malixsys/mobazoo

Hey @malixsys, danke fürs Teilen. Etwas, das ich aus Ihrem Code nicht verstehe: Es scheint, als würden Sie API_BASE_URL auf etwas Externes konfigurieren, richtig? Wenn Sie sich bei dieser API authentifizieren, würde sie wahrscheinlich eine Cookie-basierte Sitzung starten, oder? Aber wie übertragen Sie dieses Cookie dann auf den next.js-Server, vorausgesetzt, der next.js-Server befindet sich in einer anderen Domäne?

Ah nein, wie ich sehe, setzen Sie /auth/signin im gleichen Prozess. Ok, dann ist es im Grunde der gleiche Ansatz, den ich für ooth mit next.js / start verwendet habe.

Eigentlich nein, ich bin immer noch verwirrt: In /auth/signin gibt man ein JWT zurück, aber man macht auf der Client-Seite nie etwas damit. Später "getUserFromCookie", aber ich sehe nicht, wo Sie das Cookie setzen.

@nmaro Ich wollte nur, dass zunächst ein grundlegendes Login mit Universal funktioniert. Ich habe vorerst sowohl ein jwt als auch ein Cookie gesetzt. Das Cookie wird verwendet, um universell zu tun. Ich muss das jwt noch in einem anderen Axios-Aufruf in diesem Repo verwenden. Ich mache in einem privaten Fork, wo API_BASE_URL auf eine andere Domain zeigt...
Es steht alles auf meiner TODO-Liste, mit PWA.
Bitte zögern Sie nicht, ein Problem zu eröffnen oder mich hier anzupingen...

@nmaro- Cookie wird hier in saveUser() : https://github.com/malixsys/mobazoo/blob/master/utils/auth.js

Ich weiß, dass dieses Problem geschlossen ist, aber ich möchte meine Lösung zeigen.
https://next-auth.now.sh/
Ich denke, es ist ein bisschen ähnlich wie die Website von zeit.co

9. April

Ich habe etwas daran gearbeitet, derzeit überschwemmt mit anderem Zeug 😥 Das steht auf jeden Fall ziemlich weit oben auf meiner Prioritätenliste für Next

22. September #2974

Wir planen, bald ein offizielles Auth-Beispiel zu veröffentlichen. Könnten Sie dies als separates Repository veröffentlichen? Thaaaanks!

@timneutkens

Hallo, Entschuldigung, dass ich Sie erneut darüber ärgern muss, aber könnten Sie uns bitte mitteilen, wie der Status des offiziellen Authentifizierungsbeispiels ist? Es ist definitiv etwas, was ich gerne sehen würde und nach der Anzahl der Kommentare in dieser Ausgabe auch andere zu urteilen. Wie hoch ist es also auf der Prioritätenliste und sollten wir uns Hoffnungen machen? 😄

Hallo @kolpav , sie haben dies offiziell als auf der Roadmap für Next.js 5 angekündigt.

Schließlich fügen wir einige stark nachgefragte Beispiele (wie Benutzerauthentifizierung), verbesserte Dokumentation für Next.js-Interna und kleinere Funktionen und Bugfixes hinzu.

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

@babenzele Das sind tolle Neuigkeiten. Das muss ich übersehen haben

Wo können wir über die Entwicklung von Next.js 5 auf dem Laufenden bleiben? Ich integriere derzeit auth0, wäre aber toll, wenn ich einen offiziellen nextjs-Authentifizierungspfad / ein Beispiel hätte, dem du folgen könntest

Es scheint, dass Next.js dringend ein offizielles lokales Authentifizierungsbeispiel mit JWT/cookies/localStorage (oder einer Kombination davon, solange es sicher und vor XSS/CSRF geschützt ist) benötigt ... Ich habe mehrere Wochen damit verbracht, dies zu versuchen Mit einem separaten Express-API-Server mit einer lokalen Passport.js-Strategie können Sie dies erreichen. Ich habe JWT in einem Cookie/localStorage für zustandslose Anfragen ausprobiert, und ich habe auch ein reguläres Cookie mit der Sitzungs-ID der Express-Session-Middleware ausprobiert, als ich JWT und die Zustandslosigkeit endgültig aufgegeben habe. Ich bin auf Probleme gestoßen, bei denen aufgrund der Funktionsweise von Express-Session zusätzliche Sitzungen auf dem Express-API-Server erstellt wurden (versucht mit saveUninitialized: false). Ich habe überlegt, den Express-Code in meiner Next.js-App in server.js zu verschieben, aber ich hätte es wirklich lieber, wenn es ein separater Server wäre. Ich bin mir auch ziemlich sicher, dass meine Implementierung nicht sicher vor XSS/CSRF oder Cookie-Hijacking ist. Wir brauchen ein offizielles Beispiel, das Best Practices für die lokale Authentifizierung/Anmeldung abdeckt, oder vielleicht ein offizielles Modul als Teil von Next.js, das die Komplexität für uns übernimmt!

Während wir auf Next.js 5.x und weitere Beispiele warten, möchten Sie vielleicht einen Blick auf https://nextjs-starter.now.sh werfen, das immer noch aktiv gepflegt wird und Next.js mit Express, Express Sessions, CSRF ( CRSF-Token), XSS (nur HTTP-Cookies für Sitzungstoken) und verwendet Passport JS zur Unterstützung von oAuth und E-Mail.

Ich bin gerade dabei, den Authentifizierungscode in ein Modul umzuwandeln, was es wirklich einfach macht, Next.js-Projekten auf einfache Weise eine Authentifizierung hinzuzufügen. Das Modul sollte es Ihnen ermöglichen, es problemlos mit jeder beliebigen Datenbank zu verwenden, ohne eine Menge Code aus dem Starter-Projektbeispiel kopieren zu müssen. Ich hoffe, dass ich diese Woche damit fertig bin.

Als Referenz bietet die Methode "Double Submit Cookie" eine einfache Möglichkeit, den CSRF-Schutz hinzuzufügen, wenn Sie nach einem einfachen, aber sicheren Ansatz suchen.

Das Problem mit JWT in localStorage ist, dass es immer von clientseitigem JavaScript gelesen werden kann, also einem Vektor für Session-Hijacking über XSS, wenn Sie nicht vertrauenswürdigen Inhalt haben (zB von Benutzern eingereichte Inhalte oder Anzeigen).

Wenn Sie HTTP Only-Cookies für Sitzungstoken verwenden – oder so etwas wie ein JWT mit einem Tokenwert in einem HTTP Only (oder das gesamte JWT verschlüsseln und mit einem HTTP Only-Token auf dem Server entschlüsseln) – dann sind Sitzungen so geschützt wie möglich Sein. Die Idee ist nur, dass Sitzungstoken idealerweise nicht über clientseitiges JavaScript gelesen werden können.

Natürlich verwenden viele Websites keine HTTP Only-Cookies, da dies für Single Page Apps mühsam ist und ausnahmslos eine Authentifizierungslogik im Frontend erfordert, aber es ist immer noch der ideale Ansatz.

Eine andere Option ist immer noch https://github.com/nmaro/ooth, die aktiv gepflegt wird, bereits in Paketen vorliegt und in einigen Produktions-Apps verwendet wird.

@iaincollins Ich habe das Next.js-

Hallo @kelleg1 ,

Das separate Modul wird jetzt als next-auth- Modul veröffentlicht, um die Verwendung in anderen Projekten zu erleichtern. Es enthält ein Beispielprojekt, das zeigt, wie es verwendet wird.

Als weitere Referenz verwendet das nextjs-starter.now.sh- Projekt jetzt auch die next-auth, was den Code im Starter-Projekt stark vereinfacht - und es ist jetzt viel einfacher, Unterstützung für neue oAuth-Anbieter hinzuzufügen oder mit anderen Datenbanken zu verwenden ( obwohl das Beispiel immer noch Mongo DB verwendet).

Es ist jedoch immer noch etwas kompliziert, wenn Sie also eine vorhandene App haben, ist es möglicherweise einfacher, sie als Referenz zu verwenden, aber wenn ja, hoffe ich, dass es hilft

NB: CSRF ist derzeit noch ziemlich eng daran gekoppelt. Es verwendet lusca, nimmt also an, dass res.locals._csrf gesetzt ist, aber verschiedene CSRF-Bibliotheken verwenden unterschiedliche private Vars.

Ich weiß, dass die Verwendung immer noch komplizierter ist, als es jedem lieb ist, aber zumindest ist der Authentifizierungscode jetzt endlich in ein Modul unterteilt, damit ich mit der Umgestaltung beginnen kann. Ich hoffe, es im Laufe der Zeit einfacher zu verwenden (mit Standardhandlern für verschiedene Datenbanken und einfacherer Konfiguration von oAuth).

@iaincollins es sieht so aus, als ob die einzige Abhängigkeit von next.js https://github.com/iaincollins/next-auth/blob/master/index.js#L342 ist ? Wenn ja, wäre es großartig, die lib next.js-agnostisch zu machen.

@sedubois Stimme voll und ganz zu!

Obwohl dies wahrscheinlich eine gute Diskussion für die GitHub-Repo-Probleme ist und nicht hier. 🙂 Wenn Sie Verbesserungs-, Vereinfachungs- und allgemeinere Verbesserungsmöglichkeiten vorschlagen möchten, würden Sie gerne zusammenarbeiten.

(Es ist immer noch ein primäres Ziel, etwas so einfach wie möglich mit next zu verwenden, aber ich sehe nicht, dass es exklusiv sein muss, selbst wenn es am Ende auch mit den nächsten spezifischen fokussierten Optionen endet.)

@timneutkens Herzlichen Glückwunsch zur Veröffentlichung von nextjs 5. Wird in naher Zukunft ein offizielles lokales Authentifizierungsbeispiel zum Beispielordner hinzugefügt? Oder ist das noch in Arbeit für eine spätere Veröffentlichung?

Ooth verfügt jetzt über eine umfassende Dokumentation, einschließlich der Besonderheiten der next.js-Authentifizierung .

@jaredpalmer Ich mag deinen Ansatz, ich habe Teile deiner Implementierung kopiert. getUser Methode

Sie sollten es in einem Cookie speichern. Ich habe das geschrieben, bevor Next benutzerdefinierte Server unterstützte.

@jaredpalmer Kannst du mir mehr darüber erzählen? Sollten wir alles in Cookies und nicht in lokaler Speicherung speichern? Wäre Ihr HOC auch anders? Bedeutet das, dass wir jetzt die Methode getInitialProps für das serverseitige Rendern geschützter Websites verwenden können?

Nur ein Hinweis, _wenn Sie von der Speicherung sensibler Daten im lokalen Speicher / Webspeicher sprechen_:

"Speichern Sie niemals sensible Daten mit Web Storage: Web Storage ist kein sicherer Speicher. Es ist nicht „sicherer“ als Cookies, da es nicht über das Kabel übertragen wird. Es ist nicht verschlüsselt. Es gibt kein sicheres oder nur HTTP-Flag, also dies ist kein Ort, um Sitzungs- oder andere Sicherheitstoken aufzubewahren."

Setzen Sie das Token nach der Anmeldung in einem Cookie. Cookie-js verwenden. Verwenden Sie dann den Express-Cookie-Parser auf dem Server, damit Sie nach get req.headers.cookies.myToken oder gleichwertig suchen können. Überprüfen Sie in getInitialProps eines hoc, ob req existiert, und holen Sie sich dann das Token aus req.cookies, andernfalls holen Sie es auf dem Client von Cookies.get('mytoken'). An diesem Punkt haben Sie Zugriff auf Ihr Token auf dem Client und Server. Dann möchten Sie einen fetch/axios-Wrapper/eine Instanz erstellen und sie mit der ctx von next in getInitialProps zusammenführen, damit alle Ihre Seiten eine Möglichkeit haben, authentifizierte isomorphe Anfragen zu stellen. Sie können Ihren Benutzer auch nur in den Hoc bringen. Das müssen Sie also nicht überall wiederholen. Sie können dann bei Bedarf weitere Hocs für allgemeine Entitäten wie withUser(withTeam(Page)) erstellen.

getUser ist eine schlechte Idee, Sie sollten nur das Token speichern.

@jaredpalmer Ich habe einen Ansatz fast genau so gebaut und alles funktioniert gut. Das Problem, das ich jetzt zu lösen versuche, ist die Aktualisierung der Token. Die API, mit der ich arbeite, hat relativ kurzlebige Token (2 Stunden) und ich versuche, mich mit einem System zu beschäftigen, damit der Benutzer während der Verwendung der App angemeldet bleibt.
Hast du dazu einen Input?

Sie können auch bei jedem Seitenwechsel eine Anfrage speichern, indem Sie keine Daten für Ihren Benutzer durch next.js weiterleiten. Dazu würden Sie das Token aus dem Cookie in server.js lesen und versuchen, den Benutzer abzurufen und diesen an den Request-Handler des nächsten weiterzuleiten. Holen Sie es im Dokument von props und speichern Sie es in JSON auf wie window.USER. Dann lesen Sie es in Ihrem hoc einfach aus dem Fenster, wenn Sie sich im Client-Land befinden. Schließlich sollten Sie axios mit einem Response-Interceptor verwenden, der Ihr Cookie nach Erhalt des 403-Codes sofort löscht und die Seite neu lädt

@pbrandone Auch wenn es sich wiederholt, besteht die einfachste und vorhersehbarste Lösung darin, Ihr Token bei jeder Anfrage zu senden und ein neu aktualisiertes Token im Header/Textkörper der Antwort zu erhalten. Ihr Client aktualisiert seinen bekannten Wert bei jedem Anfrage-/Antwort-Zyklus und gewährt effektiv Einweg-Token, die nie veraltet sind und nicht missbraucht werden können.

Normalerweise wird bei diesem Ansatz /token/refresh nur für das anfängliche "Aufwachen" der Anwendung verwendet (denken Sie an componentWillMount Hook für <App/> ), um zu prüfen, ob die zuletzt gespeicherte Token ist noch gültig und verwendbar.

Ich musste mich nie mit Refresh-Token befassen, aber ich würde versuchen, es in einem Axios-Abfangjäger zu tun. Müsste mehr darüber nachdenken, aber theoretisch würden Sie eine schlechte Anforderung abfangen, dann mit dem Refresh-Token ein neues Token abrufen, das Cookie mit dem neuen Token setzen und die erste Anfrage mit dem neuen Token erneut abspielen. Axios-Interceptors sind wirklich mächtig, weil sie es Ihnen ermöglichen, solche Dinge abstrahiert und aus dem Blickfeld Ihres Produktcodes zu halten. Möglicherweise müssen Sie einen Request- und Response-Interceptor schreiben und/oder eine Art zustandsbehaftetes Objekt/eine Karte in Bearbeitung halten, die haarig werden könnte. Hoffentlich hilft das

Oder tun Sie, was Luke gesagt hat. Viel einfacher.

Wenn Sie Token aktualisieren möchten, müssen Sie das Cookie (wenn Sie Cookies verwenden) über eine benutzerdefinierte Servereinrichtung abfangen. Ich habe dies mit Express gemacht. Andernfalls können Sie dies alles clientseitig mit JWT-Token tun. Da ich meine über Cookies gemacht habe, hatte ich 2 Anwendungsfälle - die Handhabung von Navigationsanfragen auf der Clientseite und Seitenanfragen auf der Serverseite (immer wenn jemand manuell eine URL eingibt oder auf die Seitenaktualisierung klickt.) Aber im Grunde sind sie der gleiche Ablauf wird nur anders ausgeführt, da einer clientseitig und einer serverseitig ist. Auf der Serverseite habe ich, seit ich Express verwendet habe, gerade eine Middleware erstellt, um das Cookie zu verarbeiten, das darin enthaltene JWT zu entschlüsseln und den Ablauf zu überprüfen. Wenn es abgelaufen ist, stellen Sie eine Anforderung zum Abrufen eines neuen Tokens und übergeben Sie den decodierten Benutzer weiterhin an Redux auf dem Client. Auf dem Client habe ich einen HOC-Wrapper für sichere Links, der ständig nach dem Benutzer sucht, jedes Mal, wenn Sie irgendwo auf dem Client navigieren. Das HOC holt sich Ihr Cookie oder JWT (in meinem Fall ist mein JWT in einem Cookie) und prüft schnell, ob es noch gültig ist. Wenn es nicht gültig ist, versucht es, ein aktualisiertes JWT/Cookie zu erhalten, und fährt fort, andernfalls werden Sie abgemeldet. Ja komplizierter, aber auch sicherer. Ich hoffe, das hilft! Bei Interesse gerne Fragen stellen - ich habe eine Weile gebraucht, um alles herauszufinden. Ich persönlich frage mich, ob sich Leute mit Github oder FB usw. anmelden - wahrscheinlich für viele Fälle in Ordnung, aber in einigen Fällen ist es einfach nicht professionell. Ich habe noch keine Bank, das Gesundheitswesen, meine Rechnungen usw. gesehen - melde mich mit meinem FB-Konto an. Könnte aber nur eine Frage der Zeit sein ;)

Was das Aktualisieren von Zugriffstoken betrifft;
Ich bin mir nicht sicher, ob dies der richtige Weg ist, aber meine Zugriffstoken sind sehr kurzlebig (etwa eine Minute). Um mit clientseitigen Token-Ablaufproblemen umzugehen, habe ich diesen Ansatz gewählt;
Jedes Mal, wenn eine Seite geladen wird, überprüft sie, ob das Token abgelaufen ist, und aktualisiert es in diesem Fall. Wenn es jedoch noch gültig ist, ruft es eine Methode auf, die überprüft, wie viel Zeit bis zum Ablauf vergeht, und ein Zeitlimit festlegt, das das Zugriffstoken nach Ablauf aktualisiert. Und dann wiederholt dieser Vorgang, solange der Besucher auf der Website ist.

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

Dies gibt Millisekunden bis zum Ablauf zurück:

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

Jedes Feedback zu diesem Ansatz wäre sehr willkommen

@kunokdev - Ich denke, das ist ein guter Anfang. Ich habe eine ähnliche Funktion, bei der ich die verbleibende Zeit berechnen musste, in eine Funktion verschoben, die nur einen booleschen Wert zurückgegeben hat, je nachdem, ob sie abgelaufen war oder nicht, und das machte meinen Code etwas lesbarer und einfacher und ich musste mich nicht um das Zurücksetzen von Timern kümmern. Dann überprüfe ich einfach, ob der Benutzer abgelaufen ist oder nicht bei einer Anfrage, die eine Authentifizierung erfordert. Wenn ich einen Countdown-Timer oder ähnliches hätte, der für den Client oder das Debuggen sichtbar wäre, wäre Ihre Funktion ideal. Das sind meine 2 Cent

Sollte das Authentifizierungs-/Login-Beispiel nicht das einfachste sein, das möglich ist? dh Speicher und kein JWT oder seltsame Token-Dinge. Wenn Sie an jemanden denken, der sich "angemeldet" hat, bedeutet dies normalerweise, dass er ein Cookie/eine aktive Sitzung hat.

Ich habe ein Login HOC, das Client- und Serverseite arbeitet. Es verwendet ein JWT und ein Backend (kann Knoten, Django, was auch immer sein).

Schau es dir an und jedes Feedback ist sehr willkommen

https://github.com/hugotox/AppStarter

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

@hugotox Ich mag die Idee, Redux Store zum Speichern von Authentifizierungsdaten zu verwenden, aber wenn Sie store.dispatch von getInitialProps mehrmals aufrufen, seien Sie bereit für unerwünschte Nebeneffekte, wenn die dekorierte Komponente gerendert wird, auch wenn der Authentifizierungsprozess ist noch nicht fertig. Nehmen wir ein Anwendungsbeispiel aus Ihrem Code:

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

In getInitialProps rufen Sie verifyToken vor verificationOk , also wird MyPage.mapStateToProps 2 Mal aufgerufen (wenn es auf store.auth.user wartet) und zum ersten Mal store.auth.user wird auch für eine Seite null sein, die einen angemeldeten Benutzer erfordert.

Gestern habe ich auch die erste WIP-Version des eigenen Next.js-basierten Starterkits veröffentlicht, aber ich habe mit Docker, Flow und fast-redux angefangen: https://github.com/dogada/microchain

Ich verwende dort dedizierte Docker-Images für API-Server und Webapp, die auf verschiedenen Domänen ausgeführt werden können, daher suche ich immer noch nach einer funktionierenden Lösung, die es ermöglicht, echte Benutzer anzumelden, aber auch OAuth-Bearer-Token zum Beispiel für mobile Clients auszugeben.

@spencersmb ausgezeichneter

@james-ff Danke, dass du das gepostet hast, auch wenn es sich anfühlt, als würde man ins Leere schreien.

Es wurde in diesem Thread ein paar Mal gesagt, aber alle ignorieren anscheinend immer noch, dass sie Session-Tokens nicht in JWT mit localStorage oder in JavaScript-zugänglichen Cookies speichern sollten, und scheint die Absicht zu haben, Sessions und Authentifizierung auf weniger sichere Weise neu zu erfinden (und das erfordert clientseitiges JS). ️

Der Autor dieses Beitrags hat 2016 großartig aufgeschrieben, was daran falsch ist, aber leider scheinen sich die Dinge nicht verbessert zu haben:

Leider scheint es, dass ich die Obergrenze der Artikellänge gefunden habe, bevor die Leute aufhören zu lesen - viele der Kommentatoren von Reddit und Hacker News schlugen immer wieder die gleichen "Lösungen" vor und ignorierten völlig, dass sie bereits angesprochen und für unpraktisch befunden wurden im Artikel selbst.

Sowohl der Originalartikel als auch das Nachfolgediagramm sind jedoch ziemlich großartig.

@iaincollins JWTs und sitzungslose Apps/Authentifizierung haben ihre Vorteile und viele Leute/Unternehmen (einschließlich Google) möchten sie immer noch verwenden. Nachdem ich den Fall gegen JWTs gelesen

Ich habe dies nur beiläufig im Auge behalten, aber meine Erfahrung mit der universellen JS-Authentifizierung ist, ein JWT in einem HttpOnly Cookie zu speichern. Es gibt wirklich keinen Grund, localStorage wenn Sie die Möglichkeit haben, die Serverseite der App zu verwenden, um das Cookie zu speichern. Wenn Sie Zugriff auf das JWT für ursprungsübergreifende API-Aufrufe im Browser benötigen, können Sie das JWT in einem Szenario vom Typ __INITIAL_STATE__ (beachten Sie XSS-Schwachstellen, aber zumindest "speichern" Sie nicht es clientseitig). Für den gleichen Ursprungszugriff wird das Cookie hin und her übergeben (vorausgesetzt, Sie verwenden withCredentials für Axios oder credentials: 'include' für den Abruf), sodass das JWT überhaupt nicht in JS abgelegt werden muss . Sie könnten einen Proxy auf der Serverseite der App verwenden, um das JWT aus dem HttpOnly Cookie zu holen, _dann_ auch Ihre ursprungsübergreifenden API-Aufrufe ausführen. Auch in diesem Szenario negieren Sie den Preflight-Aufruf. Jedem das seine, aber ich persönlich glaube nicht, dass localStorage für universelle Apps benötigt wird.

@bjunc Ja, von allen Optionen, wo ein JWT gespeichert werden soll (localStorage vs. HttpOnly-Cookie vs. Redux oder was auch immer), könnte ich mich irren, aber ich denke, die Antwort sollte grundsätzlich immer ein HttpOnly-Cookie sein. Dies scheint in zahlreichen Blogs und Foren unzählige Male gesagt worden zu sein. (Ich bin mir bei Aktualisierungstoken nicht sicher - vielleicht sollten sie auch in einem HttpOnly-Cookie gespeichert werden?) Ich denke, wo JWTs gespeichert werden, sollte eine gelöste Angelegenheit sein, die sich von den übrigen Vor- und Nachteilen von JWTs unterscheidet.

Ich habe versucht, mehr oder weniger genau das zu tun, was Sie in einem meiner Projekte gesagt haben, bevor ich anfing, nextjs-starter und next-auth zu übernehmen. Es ist schon eine Weile her, aber wenn ich mich richtig erinnere, denke ich, dass das Problem, auf das ich gestoßen bin, darin bestand, dass mein Express-API-Server, gegen den ich mich authentifizierte (der Express-Session verwendete), die Sitzung nicht korrekt initialisierte/abholte. Ich würde ein seltsames Verhalten bekommen, wenn Sitzungen mehrmals initialisiert wurden. Ich beabsichtige, mehr oder weniger das zu tun, was Sie beschrieben haben, wenn ich das beheben kann. Ich werde auch weiterhin mit nextjs-starter und next-auth arbeiten, da Sessions viele der anderen Bedenken, die JWTs aufwerfen, beseitigen, z. B. wie Token ungültig gemacht werden können.

Auch hier wäre ein offizielles Beispiel (oder Beispiele) hilfreich. Stichwort: offiziell, d.h. die Autoren von Next.js haben alle Möglichkeiten abgewogen und die besten Ideen und Praktiken darin einfließen lassen. Idealerweise mit modernen ES6/ES7/ES8-Features wie Promises und Async/Await.

@kelleg1 es hört sich so an, als ob Ihre Probleme mit den Besonderheiten der Cookie-Erstellung zusammenhängen. Sie können beispielsweise versehentlich mehrere Cookies mit demselben Namen erstellen, indem Sie unterschiedliche Einstellungen verwenden ( HttpOnly , Domäne, Pfad, Ablaufdatum usw.); was zu seltsamen Nebenwirkungen führen kann, wie Sie es beschreiben. Eine Möglichkeit, dies zu debuggen, besteht darin, die Entwicklungstools Application->Cookies zu verwenden. Wenn Sie eine Reihe von Cookies mit demselben Namen sehen, weist dies möglicherweise in die richtige Richtung.

Wie auch immer, ich gehöre nicht zum Kernteam, daher kann ich mit einem "offiziellen" Beitrag nicht helfen (und tatsächlich verwende ich Nuxt.js, nicht Next.js), aber die Prinzipien sind die gleichen. Ich habe mit ein paar verschiedenen Methoden experimentiert (Abwägen der Vor- und Nachteile von JWT, Cookies, CSFR, Websocket CSWSH, localStorage usw.). Letztendlich kam ich zu dem Schluss, dass sich die universelle Natur von Next/Nuxt gut für die Verwendung von HttpOnly JWT-Cookies eignet. Vielleicht würden andere zu einem anderen Schluss kommen, aber ich persönlich bin nicht im Lager von "Oh Gott, benutze kein JWT, hast du nicht den Artikel gelesen, der sagt, dass JWT Krebs verursacht!?".

@iaincollins Entschuldigung, dass ich dies noch einmal zurückbringen muss, aber jedes einzelne Tutorial im Web verwendet localStorage, um das Token zu speichern, und Sie sagen, dass es unsicher ist. Wenn ja, wo sollen wir das Token aufbewahren?

KEKSE! :D
wir verwenden so etwas:

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

Ein wenig klobig, aber ziemlich sicher, da Javascript auf Client-Seite nie ein Token sieht und Cookie nur httpOnly ist, sicher, signiert und automatisch von axios oder einem anderen...

Hallo zusammen, habe gerade ein Authentifizierungsbeispiel mit Cookies und Redux erstellt. Siehe hier https://github.com/zeit/next.js/pull/4011

Warten Sie, wo ist dieses Problem gelandet? Ich konnte im offiziellen Repo nie ein Express-Authentifizierungsbeispiel finden.

Ich sehe viel von Cookies und Sitzungen, aber wie funktioniert das für meine native mobile App, wenn sie die API erreichen muss?

Es kann getan werden, aber dafür ist JWT da :p

Ich habe gerade den gesamten Thread ausführlich gelesen und fühle mich gezwungen, meine Ergebnisse zusammenzufassen.

Es scheint, dass es zwei praktikable Starterprojekte gibt, bei denen solide Authentifizierungsmodule ausgeklammert sind:

Ausgezeichnete Arbeit von @iaincollins und @nmaro !

Danke @curran :)

Ich habe alle Codeänderungen, die ich zum Entfernen der überflüssigen Aspekte von nextjs-starter vorgenommen habe, in diesem Pull Request dokumentiert https://github.com/iaincollins/nextjs-starter/pull/86

Dies könnte einem soliden Barebone-Authentifizierungsbeispiel für das Next.js-Repository näher kommen.

Ich hatte vor kurzem die Anforderung, OAuth mit Office 365 zu implementieren, also dachte ich, ich würde ein sehr einfaches Beispiel teilen, das ich hier zusammengewürfelt hier beschriebene Thread für geschützte Routen. Auf jeden Fall dachte ich mir, ich würde es mitteilen, falls jemand ein kurzes Beispiel dafür haben möchte, wie dies (vielleicht) mit Microsoft gemacht wird.

Für alle, die an einer einfachen JWT-tokenisierten Authentifizierung interessiert sind, die client- und serverseitig funktioniert, habe ich im Spectrum-Chat Hilfe geholt und dachte, ich würde sie mit Ihnen allen teilen. Jedes Feedback ist immer willkommen.

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

Hallo Leute!
Hier ist ein weiteres Beispiel für die Authentifizierung mit next.js, das ich vor ein paar Monaten erstellt habe, vielleicht findet es jemand nützlich:

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

Ooth 2.0 ist raus mit neuen und besseren Dokumenten

Ooth ist ein Benutzeridentitätsverwaltungssystem , das für node.js (mit Blick auf next.js) entwickelt wurde.

Derzeit unterstützte Strategien:

  • Primär: Benutzername/Passwort (inkl. E-Mail bestätigen, Pw vergessen etc.), Gast, Facebook, Google
  • Sekundär: Cookie-basierte Sitzungen, JWTs

Schauen Sie sich dieses Live-Beispiel an , das alles mit next.js ( Quellcode ) zusammenfasst.

Viele der Auth-Beispiele hier (und im Beispielordner) geben den Benutzer session/token/etc von getInitialProps . Soweit ich weiß, bedeutet dies, dass die Benutzersitzungsinformationen beim Rendern der Seite serverseitig als Teil der HTML-Seitenantwort (als Teil von NEXT_DATA ) an den Browser gesendet werden.

Ich sehe bei diesem Muster zwei Sicherheitsprobleme, wenn getInitialProps serverseitig ausgeführt wird:
1) Die Benutzersitzung wird über das Netzwerk vom Server zum Browser übertragen. Wenn solche Anfragen http:// und nicht https:// , wird das Token des Benutzers usw. im Klartext über das Netzwerk verfügbar gemacht.

2) Die Benutzersitzung wird als Teil der HTML-Seite vom Server an den Browser zurückgegeben (in einem NEXT_DATA Skript-Tag). Es erscheint riskant, das Token/usw. des Benutzers direkt auf der HTML-Seite zu platzieren, insbesondere wenn die Seite geparst und vom Browser gerendert wurde und andere Skripte von Drittanbietern jetzt möglicherweise ausgeführt werden.

Sind das bereits angesprochene Themen? Gibt es Gegenmaßnahmen für diese Bedrohungen?

Deshalb verwende ich Cookies. Siehe mein Beispiel hier https://github.com/hugotox/nextjs-starter/blob/master/pages/_app.js

Schließlich! Hier finden Sie ein vollständig dockerisiertes next.js-Authentifizierungsbeispiel mit den folgenden Containern:

  • next.js
  • Authentifizierungs-Microservice (ooth)
  • API (Graphql)
  • Sitzungsspeicher (redis)
  • kleiner Reverse-Proxy

Alles wird mit docker-compose zusammengezogen.

Kurze Anmerkung zu JWTs. JWTs haben den Vorteil, dass sie zustandslos, gut für Mobilgeräte und gut geeignet sind, wenn Sie Anmeldeinformationen von einer Domäne an die andere weitergeben müssen. Der Hauptnachteil ist, dass sie den Browser XSS aussetzen. Für dieses Beispiel habe ich mich für eine reine Cookie-Session-basierte Lösung entschieden. Dank des Reverse-Proxys (alle Microservices laufen unter derselben Domäne) und des gemeinsamen Sitzungsspeichers habe ich es immer noch geschafft, die Dinge in Microservices aufzuteilen.

https://github.com/nmaro/staart/tree/master/examples/staart
Das Live-Beispiel ist wie gewohnt: https://staart.nmr.io

Ich denke, es ist ratsam, klarzustellen, dass Sie durch die Verwendung von JWT nicht von Natur aus XSS "ausgesetzt" werden. Wenn Ihre Site eine XSS-Sicherheitslücke aufweist (nicht aufgrund von JWT selbst), könnte ein JWT kompromittiert werden (zusammen mit allen anderen Skript-zugänglichen Informationen); wohingegen httpOnly Cookies nicht zugänglich sind. Vergessen Sie nicht, dass Sie ein JWT als Wert eines httpOnly Cookies verwenden können!

Nur Cookie-Lösungen können für die Kommunikation über dieselbe Domain gut funktionieren, aber wenn Sie eine Headless-API haben (z. B. example.com die api.example.com aufruft), ist das keine wirkliche Lösung, es sei denn, Sie möchten einen Proxy-Browser verwenden Anfragen von example.com an api.example.com indem Sie Ihre API-Aufrufe an example.com und sie mit dem an die Anfrage angehängten Cookie weiterleiten (das mit seinen eigenen Vor- und Nachteilen verbunden ist). .

Ich persönlich halte die Nachteile von JWT für übertrieben und lassen sich durch eine Reihe von häufig implementierten Schutzmaßnahmen ziemlich leicht abmildern. Nicht zuletzt eine Token-Blacklist mit Verweis auf den jti Anspruch (zB Version4 UUID) für den Fall, dass der Token vor Ablauf kompromittiert wurde.

Hey @bjunc ja danke für die Klarstellung. Richtig, JWT setzt Sie nicht selbst XSS aus. Zu Ihren anderen Beobachtungen möchte ich hinzufügen, dass sie alle ihre Tücken haben.

Denken Sie daran, dass Sie ein JWT als Wert eines httpOnly-Cookies verwenden können!

Ja, möchte nur hinzufügen, dass dadurch der einzige Vorteil von JWT beseitigt wird, Anmeldeinformationen zwischen Domänen zu übertragen.

eine Token-Blacklist

Dies und die andere gängige Praxis eines Aktualisierungstokens beseitigen den anderen Vorteil von JWT, wirklich zustandslos zu sein.

Das ist mein Verständnis der Situation:

  • Wenn Sie eine standortübergreifende Authentifizierung
  • Wenn Sie sich von einem Client aus authentifizieren müssen, der kein Browser ist und das XSS-Problem nicht hat (z. B. eine Desktop- oder mobile App), verwenden Sie JWT
  • Verwenden Sie andernfalls Cookie-basierte Sitzungen, da eine JWT-basierte Lösung entweder weniger sicher (XSS) oder nicht wirklich zustandslos (Blacklists) ist oder Sie einen Proxy verwenden müssen, um sowieso alles unter derselben Domäne zu halten.

Ich habe einen Medium-Artikel über Next.js-Authentifizierung/Benutzerkonten geschrieben.
Es ist ein umfangreiches Tutorial und mein Braindump aus fast zwei Jahren Freizeitentwicklung und -denken (mein erster Kommentar zu dieser Ausgabe stammt vom Februar 2017).

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

Sie korrelieren JWT immer wieder damit, dass es weniger sicher ist. JWT macht Ihre Site nicht weniger sicher. Es ist an und für sich keine XSS-Sicherheitslücke. Wenn Sie einen XSS-Exploit haben, sind Sie trotzdem in gleichen Schwierigkeiten. Selbst mit einem httpOnly Cookie kann der Angreifer den Cookie-Wert möglicherweise nicht lesen, aber das spielt keine Rolle, da er beliebigen Code ausführen kann – wie XHR-Anfragen, die die Sitzungscookies automatisch passieren würden (im Wesentlichen als ein CSRF-Angriff). Wenn Ihre API domänenübergreifend ist und Sie Browser-zu-Server-Anforderungen stellen, befindet sich das JWT sowieso irgendwo im Code (sei es im Anfangszustand oder localStorage). Wenn Sie Axios verwenden, haben Sie möglicherweise sogar globale Standardeinstellungen festgelegt, bei denen der Angreifer nur eine Axios-Anfrage stellen muss und sich nicht einmal um die Authentifizierung kümmern muss.

Außerdem kann man nicht wirklich über XSS sprechen, ohne auch über CSRF zu sprechen; wo Auth-Cookies speziell ausgerichtet sind. Selbst mit einem Reverse-Proxy-Setup würde ein CSRF-Angriff dem Angreifer ermöglichen, authentifizierte Anfragen für Ihre API auszuführen.

Übrigens, nur weil Sie das JWT in einem Cookie ablegen (zum Beispiel wissen, ob der Benutzer angemeldet ist), bedeutet das nicht, dass Sie den Cookie-Wert (z. API-Serverzugriff beim Laden der Seite (der auch für das Reverse-Proxy-Szenario funktioniert). Sie sind auch nicht daran gehindert, das JWT im Anfangszustand für Browser-zu-API-Server-Anfragen zu übergeben. Sie schließen sich nicht gegenseitig aus.

Abgesehen davon finde ich die Idee des "zustandslosen" JWT sowohl überbewertet als auch in der Anwendung für die meisten Anwendungsfälle eingeschränkt. Zum Beispiel:

  • Ressourcenbasierte / dynamische Berechtigungen (zB nicht nur " can edit Post ", sondern eher " can edit Post:1634 ").
  • Was ist, wenn das Konto des Benutzers gesperrt / gelöscht wurde?
  • Sie haben ihr monatliches Abonnement nicht bezahlt; welche drosselt die funktion?
  • Das Token auf die schwarze Liste gesetzt (wie oben)?

Sie backen nicht all das in das JWT, was bedeutet, dass Sie in die Domänenschicht (dh die Datenbank) eintauchen müssen, um dies herauszufinden. Sie haben die Ressource gerade geladen, können sie also genauso gut dort platzieren, wo der Rest der App darauf zugreifen kann, und jetzt haben Sie den Status. Ich finde es wirklich albern zu glauben, dass alles, was Sie über das Thema wissen müssen, in das Token eingebrannt wird; während es gleichzeitig meistens anonym und leichtgewichtig bleibt. Ohne zu viel abzuschweifen, gibt es ein Argument für "zustandslose" Anfragen in der Kommunikation zwischen Diensten, aber selbst das finde ich unpraktisch (zumindest was das Konzept betrifft, alles, was Sie über das Thema wissen müssen, in das JWT zu übertragen). .

Inzwischen verfügbare Ooth-Authentifizierungsstrategien (neu in Fettdruck):

  • Lokal (Benutzername/E-Mail/Passwort)
  • Facebook
  • Google
  • Gast
  • Patreon
  • Twitter
  • Authy (Twilio) - passwortlos per SMS

@jaredpalmer du hast geschrieben
Wie bei PHP ist die atomare Einheit von Next die Seite. Eine der coolsten Funktionen ist, dass jede Seite nur dann geladen wird, wenn sie angefordert wird. Bei nur clientseitiger Authentifizierung, aber beim Server-Rendering wird das js für diese geschützte Seite tatsächlich vom Browser heruntergeladen. Wenn Next in Zukunft Server-Workflows hinzufügt, können Sie hoffentlich das Rendern und die Umleitung auf dem Server blockieren, um dies vollständig zu verhindern. Dies erfordert Cookies, Sitzungen und AFAIK-Sitzungsspeicher, aber das sind nur die Kosten für solche Hybrid-Apps.

Wir sind 2 Jahre später. Gibt es einen Server-Workflow, um das Laden von js für geschützte Seiten zu verhindern?
@timneutkens vielleicht geschützte Inhalte in eine andere Zone stellen?
Wie würde ich den Zugriff auf geschützte Inhalte vollständig verhindern?

@lishine Du hast eine ServerResponse im getInitialProps deiner Seite - du kannst ganz einfach jemanden umleiten, der nicht privilegiert ist.

Gibt es ein Beispiel für Authentifizierung mit Redux?

Gibt es ein Beispiel für Authentifizierung mit Redux?

Sie können dieses Beispiel ausprobieren, das Redux verwendet, und prüfen, ob es für Sie funktioniert ...
Sie finden es irgendwo in diesem Thema, aber falls Sie es nicht finden können, hier ist es:
https://github.com/alan2207/nextjs-jwt-authentication

Ich denke, dies ist ein komplizierteres Problem, wenn die Ergebnisse des serverseitigen API-Aufrufs getInitialProps verwendet werden, da Virtual DOM alte Ergebnisse nach der LOGOUT-LOGIN-Aktion verwendet. Ich denke über eine Lösung nach

_BEARBEITET_
und hier ist meine Antwort mit redux-observable

|Seite|Auth|TODO|
|---|---|---|
|Server|true|Anfangsdaten abrufen (mit Anforderungs-Cookie-Proxy).|
|Server|false|Anmeldeseite anzeigen und Daten nach der Anmeldung abrufen.|
|Client|true|Anfangsdaten abrufen.|
|Client|false|Anmeldeseite anzeigen und Daten nach der Anmeldung abrufen. (Dies geschieht nur, wenn die Sitzung beim Verschieben von Seite zu Seite abgelaufen ist)|

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

Scheint kompliziert zu sein, wenn etwas Einfaches ausreicht, etwa wie:

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

Dieses Beispiel wurde als Teil von Next.js 8 zusammengeführt
https://github.com/zeit/next.js/tree/canary/examples/with-cookie-auth

@timneutkens danke für den Link.

siehe https://github.com/zeit/next.js/blob/canary/examples/with-cookie-auth/www/utils/auth.js#L26 -L34 checken, nachdem auth() aufgerufen wurde?

Das Testen des Beispiels ohne Cookie führt dazu, dass Profile.getInitialProps() aufgerufen wird, während ich dachte, die Umleitung würde erfolgen, bevor überhaupt versucht wird, mehr "Anfangsprops" zu erhalten ...

Ich habe hier ein Beispiel gemacht, das serverseitiges Pre-Rendering + Authentifizierung mit apollo hat

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

Bitte beachten Sie, dass die OWASP-Sicherheitsrichtlinien davon abraten, JWT-Token im lokalen Speicher zu speichern, dh "Ein einzelnes Cross Site Scripting kann verwendet werden, um alle Daten in diesen Objekten zu stehlen, daher wird erneut empfohlen, keine sensiblen Informationen im lokalen Speicher zu speichern."

Hier ist Auth0: Wo Tokens gespeichert werden und Tom Abbott: Wo Sie Ihre JWTs speichern – Cookies vs HTML5 Web Storage .

Hier ist ein Beispiel mit Nuxt.js + Express.js-Proxyserver + Django-Backend. Wo der Express-Server für die Proxy-Authentifizierungsanfrage an das eigentliche Backend verwendet wird und den CSRF-Schutz handhabt, wenn das JWT-Token in einem Cookie gespeichert wird (beschränkt die Länge des Tokens / wie viele Informationen im JWT-Token gespeichert werden können): https:/ /github.com/danjac/nuxt-python-secure-example

@timneutkens Ich benötige einige Dokumente zum Senden von Token von Cookie 🍪 an benutzerdefinierte SSR-Redux-Middleware. Ich bekomme die Cookies in _app.js . Aber wie soll ich es an customApimiddleware übergeben. Wo habe ich Abrufanfragen geschrieben. Vielen Dank

Ich habe einen Medium-Artikel über Next.js-Authentifizierung/Benutzerkonten geschrieben.
Es ist ein umfangreiches Tutorial und mein Braindump aus fast zwei Jahren Freizeitentwicklung und -denken (mein erster Kommentar zu dieser Ausgabe stammt vom Februar 2017).

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

Ich denke, dies ist eines der besten Tutorials zum Umgang mit der Authentifizierung in einer nextj.js-App. Ich habe Dinge wie das Speichern von Token in localStorage (XSS), das Speichern von Token in Cookies (ohne Umgang mit CSRF) und sogar das Speichern von Token in Cookies vom Browser (sowohl XSS als auch CSRF anfällig) gesehen.

Ich mag Ihre Lösung mit dem Reverse-Proxy und dem Teilen der Sitzungsinformationen zwischen verschiedenen Diensten sehr. Ich möchte wirklich keinen benutzerdefinierten Server für die next.js-App erstellen, aber ich denke, dies ist der einfachste Weg, um sowohl Sitzungen zu verarbeiten als auch csrf zu verhindern (und möglicherweise den Reverse-Proxy hinzuzufügen). Am Ende kann ich sogar ein Monolith-Projekt erstellen (sowohl zum Rendern der App als auch zum Behandeln von DB-Operationen usw.).

Ich habe gesehen, dass einige Leute (einschließlich ZEIT) die APIs zustandslos halten und die next.js-App die Sitzung verarbeiten lassen. Es übergibt die Token an APIs. Aber mit Sitzungen zu gehen macht die Dinge nur ein bisschen enger und weniger kompliziert.

Es wäre wirklich besser, ein vollständiges Authentifizierungsbeispiel für next.js zu haben. Mit Dingen wie der Authentifizierung für externe APIs, der Beibehaltung der Sitzung in der next.js-App, der gemeinsamen Nutzung von Sitzungen zwischen Diensten oder der Übergabe von Token an sie und möglicherweise sogar der Aktualisierung der Token, wenn sie abgelaufen sind. (Viele Leute schreiben viel über JWTs und verwenden sie nur in ihren Tutorials, aber sie lassen sie meistens nicht einmal ablaufen oder aktualisieren sie nicht einmal.)

Wie auch immer, Sie haben eines der umfassendsten Tutorials zu diesem Thema geschrieben. So danke!

Ich hoffe wirklich, dass es viel vollständigere und klarere Beispiele und Dokumentationen geben wird.

Es wäre wirklich besser, ein vollständiges Authentifizierungsbeispiel für next.js zu haben. Mit Dingen wie der Authentifizierung für externe APIs, der Beibehaltung der Sitzung in der next.js-App, der gemeinsamen Nutzung von Sitzungen zwischen Diensten oder der Übergabe von Token an sie und möglicherweise sogar der Aktualisierung der Token, wenn sie abgelaufen sind. (Viele Leute schreiben viel über JWTs und verwenden sie nur in ihren Tutorials, aber sie lassen sie meistens nicht einmal ablaufen oder aktualisieren sie nicht einmal.)

Auch ich bin ratlos, welchen Ansatz ich wählen soll.
vielen Dank für den Link zum Artikel.
Auf welche der Implementierungen haben Sie sich derzeit festgelegt?
Haben Sie ein umfassendes Autorisierungsbeispiel für next v9.3+ gefunden?

Es lohnt sich, den neuen Cookie-basierten Ansatz von Auth0 auszuprobieren
(Natürlich gilt dies für einen bestimmten Identitätsanbieter, aber der Ansatz könnte nützlich sein.)
https://github.com/auth0/nextjs-auth0

  • Wirklich cool, dass Sie API-Anfragen über die API-Routen von nextjs "proxy" können (sogar über eine dynamische Route)
  • Dann müssen Sie der Clientseite nie Zugriffstoken usw. offenlegen (da nextjs-API-Routen nur die Serverseite ausführen), kann die Serverseite Zugriffstoken usw. über die auth0-Bibliothek und das Cookie mit einem Geheimnis erhalten
  • Ihr clientseitiger Code würde Ihre nextjs-API-Routen aufrufen, und die API-Routen würden dann die echte API-Anfrage ausführen

Denken Sie daran, dass dieser Ansatz in der ReadMe-Datei "experimentell" ist

Es lohnt sich, den neuen Cookie-basierten Ansatz von Auth0 auszuprobieren
(Natürlich gilt dies für einen bestimmten Identitätsanbieter, aber der Ansatz könnte nützlich sein.)
https://github.com/auth0/nextjs-auth0

  • Wirklich cool, dass Sie API-Anfragen über die API-Routen von nextjs "proxy" können (sogar über eine dynamische Route)
  • Dann müssen Sie der Clientseite nie Zugriffstoken usw. offenlegen (da nextjs-API-Routen nur die Serverseite ausführen), kann die Serverseite Zugriffstoken usw. über die auth0-Bibliothek und das Cookie mit einem Geheimnis erhalten
  • Ihr clientseitiger Code würde Ihre nextjs-API-Routen aufrufen, und die API-Routen würden dann die echte API-Anfrage ausführen

Denken Sie daran, dass dieser Ansatz in der ReadMe-Datei "experimentell" ist

Dieser Artikel ist sehr hilfreich und deckt viele verschiedene Architekturen ab.
https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/

Die Verwendung von API-Routen als Proxy, An- und Abmeldung über API-Routen, das Abrufen des Tokens von der API und das Festlegen als HttpOnly-Cookie ist meiner Meinung nach ein solider Ansatz.
Ein Problem könnte CSRF sein, aber Sie können leicht eine Lösung mit dem csrf npm-Paket erstellen (nicht csurf , aber das könnte auch funktionieren).

@onderonur , danke für den auth0-Artikel.
das heißt, gibt es derzeit mit next.js ein zuverlässiges oder zumindest minimales Beispiel für die Implementierung auf reinem jwt?
Ich möchte keine erweiterte Ebene mit Cookies erstellen und sie einrichten. In der csr-Anwendung haben wir das Token einfach in localstorage gespeichert und zusammen mit der Anfrage gesendet.

@onderonur , danke für den auth0-Artikel.
das heißt, gibt es derzeit mit next.js ein zuverlässiges oder zumindest minimales Beispiel für die Implementierung auf reinem jwt?
Ich möchte keine erweiterte Ebene mit Cookies erstellen und sie einrichten. In der csr-Anwendung haben wir das Token einfach in localstorage gespeichert und zusammen mit der Anfrage gesendet.

Ich habe diese Methode für eines meiner Repos verwendet, aber sie ist noch im Entwurf, also teste sie selbst :)
https://github.com/onderonur/post-gallery
Eigentlich ist die "Cookie-Schicht" keine fortgeschrittene Sache. Rufen Sie einfach den Anmeldeendpunkt Ihrer API über die API-Route /api/login , und wenn die Anfrage erfolgreich ist, legen Sie das Token in einem httpOnly Cookie fest.
Sie können mein Repository für die exakt gleiche Implementierung überprüfen.

Eine andere Option ist (wenn Sie fast den gleichen Ablauf haben möchten wie das Setzen des Tokens im lokalen Speicher), können Sie das js-cookie npm-Paket verwenden, Ihren Anmeldeendpunkt mit einer clientseitigen Anfrage aufrufen und beenden, wenn es zurückkehrt ein Token, setzen Sie es in ein Cookie. Und wenn Sie eine Anfrage stellen (über einen Axios-Interceptor usw.), lesen Sie den Cookie-Wert und übergeben Sie ihn als Anfrage-Header an Ihre API. Ich habe viele (und sogar einige beliebte) Anwendungen gesehen, die diesen Ansatz verwenden. Aber das ist ein bisschen unsicher. Weil Sie im Browser keine httpOnly Cookies setzen können. JavaScript kann also Ihr Token-Cookie lesen. Daher wird es eine XSS-Sicherheitslücke geben.

Schätzen Sie, dass dies ein alter Thread (und im Allgemeinen ein lang andauerndes Thema) ist, aber für diejenigen, die nach zusätzlichen Referenzen oder Beispielen suchen, haben wir kürzlich die Arbeit an NextAuth.js v2 aufgenommen. Ich erwähne es nicht einmal als Plug-In – es ist ein Open-Source-Projekt und eine Menge Leute haben dabei geholfen – aber es ist super einfach zu bedienen und der Code und der Ansatz könnten als Referenz für die Leute nützlich sein.

Für einige Hintergründe, wie NextAuth v1, verwendet es Cookies, die signiert sind, mit einem Präfix versehen sind und nur HTTP verwenden, um die üblichen Sicherheitsfallen bei der Verwendung von clientseitigen Token zu vermeiden.

NextAuth.js v2 unterstützt die Anmeldung bei Apple, Google, Facebook, Twitter, GitHub, Auth0, Okta, Slack, Discord und anderen OAuth-Anbietern (es unterstützt sowohl 1.x als auch 2.x). Sie können es mit MySQL, MariaDB, Postgres, MongoDB verwenden - oder ohne Datenbank (nur OAuth und JSON Web Tokens für eine 100% serverlose Lösung).

Die Verwendung ist sehr einfach, es gibt eine universelle statische Methode namens session() und einen React Hook namens useSession() Sie in Komponenten clientseitig verwenden können:

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

Es wurde für Next.js 9.x und Serverless entwickelt und hat keine Abhängigkeiten wie Express oder PassportJS. Es enthält einen Authentifizierungsanbieter, den Sie in _app.js , um allen Seiten automatisch den Authentifizierungsstatus hinzuzufügen. Es funktioniert sowohl für das client- als auch für das serverseitige Rendering.

Weitere Informationen finden Sie unter next-auth.js.org oder in next-auth@beta auf NPM

Es ist noch in Arbeit - wir polieren noch die Dokumentation und das Event-Modell - mit einem angestrebten Release-Datum von ~Anfang~ Mitte Juni.

Schätzen Sie, dass dies ein alter Thread (und im Allgemeinen ein lang andauerndes Thema) ist, aber für diejenigen, die nach zusätzlichen Referenzen oder Beispielen suchen, haben wir kürzlich die Arbeit an NextAuth.js v2 aufgenommen. Ich erwähne es nicht einmal als Plug-In – es ist ein Open-Source-Projekt und eine Menge Leute haben dabei geholfen – aber es ist super einfach zu bedienen und der Code und der Ansatz könnten als Referenz für die Leute nützlich sein.

Für einige Hintergründe, wie NextAuth v1, verwendet es Cookies, die signiert sind, mit einem Präfix versehen sind und nur HTTP verwenden, um die üblichen Sicherheitsfallen bei der Verwendung von clientseitigen Token zu vermeiden.

NextAuth.js v2 unterstützt die Anmeldung bei Apple, Google, Facebook, Twitter, GitHub, Auth0, Okta, Slack, Discord und anderen OAuth-Anbietern (es unterstützt sowohl 1.x als auch 2.x). Sie können es mit MySQL, MariaDB, Postgres, MongoDB verwenden - oder ohne Datenbank (nur OAuth und JSON Web Tokens für eine 100% serverlose Lösung).

Die Verwendung ist sehr einfach, es gibt eine universelle statische Methode namens session() und einen React Hook namens useSession() Sie in Komponenten clientseitig verwenden können:

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

Es wurde für Next.js 9.x und Serverless entwickelt und hat keine Abhängigkeiten wie Express oder PassportJS. Es enthält einen Authentifizierungsanbieter, den Sie in _app.js , um allen Seiten automatisch den Authentifizierungsstatus hinzuzufügen. Es funktioniert sowohl für das client- als auch für das serverseitige Rendering.

Weitere Informationen finden Sie unter next-auth.js.org oder in next-auth@beta auf NPM

Es ist noch in Arbeit - wir polieren noch die Dokumentation und das Event-Modell - mit einem angestrebten Release-Datum von ~Anfang~ Mitte Juni.

Tolle Arbeit das!
Kann dies auf der Client-Seite allein verwendet werden? Ich habe zum Beispiel eine Rails-API-App - und verwende next JS für die Clientseite.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen