mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
820 firebase (#1756)
* connecting to firebase * login and logout with sessions * setting messages on the client side * should have messages served on init * set messages in state * updating credentials * updating readme * more cred * iron out eslint issues * highlight where to put firebase variables * fix problem of database listener not picking up changes on load * remove isomorphic from main package.json
This commit is contained in:
parent
bbb8ff75a5
commit
06baed2fe8
33
examples/with-firebase/README.md
Normal file
33
examples/with-firebase/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
# With Firebase example
|
||||
|
||||
## How to use
|
||||
|
||||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-firebase
|
||||
cd with-firebase
|
||||
```
|
||||
|
||||
Set up firebase:
|
||||
- create a project
|
||||
- get your service account credentials and client credentials and set both in firebaseCredentials.js
|
||||
- set your firebase database url in server.js
|
||||
- on the firebase Authentication console, select Google as your provider
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
## The idea behind the example
|
||||
The goal is to authenticate users with firebase and store their auth token in sessions. A logged in user will see their messages on page load and then be able to post new messages.
|
8
examples/with-firebase/firebaseCredentials.js
Normal file
8
examples/with-firebase/firebaseCredentials.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
clientCredentials: {
|
||||
// TODO firebase client config
|
||||
},
|
||||
serverCredentials: {
|
||||
// TODO service account json here
|
||||
}
|
||||
}
|
19
examples/with-firebase/package.json
Normal file
19
examples/with-firebase/package.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"scripts": {
|
||||
"dev": "node server.js",
|
||||
"build": "next build",
|
||||
"start": "NODE_ENV=production node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.17.1",
|
||||
"express": "^4.14.0",
|
||||
"express-session": "^1.15.2",
|
||||
"firebase": "^3.7.5",
|
||||
"firebase-admin": "^4.2.0",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"next": "latest",
|
||||
"react": "^15.4.2",
|
||||
"react-dom": "^15.4.2",
|
||||
"session-file-store": "^1.0.0"
|
||||
}
|
||||
}
|
115
examples/with-firebase/pages/index.js
Normal file
115
examples/with-firebase/pages/index.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
import React, { Component } from 'react'
|
||||
import firebase from 'firebase'
|
||||
import 'isomorphic-fetch'
|
||||
import { clientCredentials } from '../firebaseCredentials'
|
||||
|
||||
export default class Index extends Component {
|
||||
static async getInitialProps ({req, query}) {
|
||||
const user = req && req.session ? req.session.decodedToken : null
|
||||
const snap = await req.firebaseServer.database().ref('messages').once('value')
|
||||
return { user, messages: snap.val() }
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
user: this.props.user,
|
||||
value: '',
|
||||
messages: this.props.messages
|
||||
}
|
||||
|
||||
this.addDbListener = this.addDbListener.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
firebase.initializeApp(clientCredentials)
|
||||
|
||||
if (this.state.user) this.addDbListener()
|
||||
|
||||
firebase.auth().onAuthStateChanged(user => {
|
||||
if (user) {
|
||||
this.setState({ user: user })
|
||||
return user.getToken()
|
||||
.then((token) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
return fetch('/api/login', {
|
||||
method: 'POST',
|
||||
// eslint-disable-next-line no-undef
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ token })
|
||||
})
|
||||
}).then((res) => this.addDbListener())
|
||||
} else {
|
||||
this.setState({ user: null })
|
||||
// eslint-disable-next-line no-undef
|
||||
fetch('/api/logout', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin'
|
||||
}).then(() => firebase.database().ref('messages').off())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
addDbListener () {
|
||||
firebase.database().ref('messages').on('value', snap => {
|
||||
const messages = snap.val()
|
||||
if (messages) this.setState({ messages })
|
||||
})
|
||||
}
|
||||
|
||||
handleChange (event) {
|
||||
this.setState({ value: event.target.value })
|
||||
}
|
||||
|
||||
handleSubmit (event) {
|
||||
event.preventDefault()
|
||||
const date = new Date().getTime()
|
||||
firebase.database().ref(`messages/${date}`).set({
|
||||
id: date,
|
||||
text: this.state.value
|
||||
})
|
||||
this.setState({ value: '' })
|
||||
}
|
||||
|
||||
handleLogin () {
|
||||
firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider())
|
||||
}
|
||||
|
||||
handleLogout () {
|
||||
firebase.auth().signOut()
|
||||
}
|
||||
|
||||
render () {
|
||||
const { user, value, messages } = this.state
|
||||
|
||||
return <div>
|
||||
{
|
||||
user
|
||||
? <button onClick={this.handleLogout}>Logout</button>
|
||||
: <button onClick={this.handleLogin}>Login</button>
|
||||
}
|
||||
{
|
||||
user &&
|
||||
<div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<input
|
||||
type={'text'}
|
||||
onChange={this.handleChange}
|
||||
placeholder={'add message'}
|
||||
value={value}
|
||||
/>
|
||||
</form>
|
||||
<ul>
|
||||
{
|
||||
messages &&
|
||||
Object.keys(messages).map(key => <li key={key}>{messages[key].text}</li>)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
63
examples/with-firebase/server.js
Normal file
63
examples/with-firebase/server.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const session = require('express-session')
|
||||
const FileStore = require('session-file-store')(session)
|
||||
const next = require('next')
|
||||
const admin = require('firebase-admin')
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production'
|
||||
const app = next({ dev })
|
||||
const handle = app.getRequestHandler()
|
||||
|
||||
const firebase = admin.initializeApp({
|
||||
credential: admin.credential.cert(require('./firebaseCredentials').serverCredentials),
|
||||
databaseURL: '' // TODO database URL goes here
|
||||
}, 'server')
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
server.use(bodyParser.json())
|
||||
server.use(session({
|
||||
secret: 'geheimnis',
|
||||
saveUninitialized: true,
|
||||
store: new FileStore({path: '/tmp/sessions', secret: 'geheimnis'}),
|
||||
resave: false,
|
||||
rolling: true,
|
||||
httpOnly: true,
|
||||
cookie: { maxAge: 604800000 } // week
|
||||
}))
|
||||
|
||||
server.use((req, res, next) => {
|
||||
req.firebaseServer = firebase
|
||||
next()
|
||||
})
|
||||
|
||||
server.post('/api/login', (req, res) => {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
|
||||
const token = req.body.token
|
||||
firebase.auth().verifyIdToken(token)
|
||||
.then((decodedToken) => {
|
||||
req.session.decodedToken = decodedToken
|
||||
return decodedToken
|
||||
})
|
||||
.then((decodedToken) => res.json({ status: true, decodedToken }))
|
||||
.catch((error) => res.json({ error }))
|
||||
})
|
||||
|
||||
server.post('/api/logout', (req, res) => {
|
||||
req.session.decodedToken = null
|
||||
res.json({ status: true })
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(3000, (err) => {
|
||||
if (err) throw err
|
||||
console.log('> Ready on http://localhost:3000')
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue