1
0
Fork 0
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:
captDaylight 2017-04-22 07:56:28 -05:00 committed by Tim Neutkens
parent bbb8ff75a5
commit 06baed2fe8
5 changed files with 238 additions and 0 deletions

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

View file

@ -0,0 +1,8 @@
module.exports = {
clientCredentials: {
// TODO firebase client config
},
serverCredentials: {
// TODO service account json here
}
}

View 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"
}
}

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

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