working login
This commit is contained in:
parent
cfa55f5cf1
commit
df40e5d37a
|
@ -24,6 +24,7 @@
|
||||||
"babel-preset-es2015": "^6.9.0",
|
"babel-preset-es2015": "^6.9.0",
|
||||||
"babel-preset-react": "^6.11.1",
|
"babel-preset-react": "^6.11.1",
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "^0.23.1",
|
||||||
|
"dotenv": "^2.0.0",
|
||||||
"file-loader": "^0.9.0",
|
"file-loader": "^0.9.0",
|
||||||
"html-webpack-plugin": "^2.22.0",
|
"html-webpack-plugin": "^2.22.0",
|
||||||
"postcss": "^5.0.21",
|
"postcss": "^5.0.21",
|
||||||
|
@ -36,6 +37,8 @@
|
||||||
"webpack-dev-server": "^1.14.1"
|
"webpack-dev-server": "^1.14.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"auth0-lock": "^10.0.0",
|
||||||
|
"jwt-decode": "^2.1.0",
|
||||||
"postcss": "^5.1.0",
|
"postcss": "^5.1.0",
|
||||||
"react": "^15.2.1",
|
"react": "^15.2.1",
|
||||||
"react-dom": "^15.2.1"
|
"react-dom": "^15.2.1"
|
||||||
|
|
|
@ -1,12 +1,54 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import AuthService from '../../utils/AuthService'
|
||||||
import './App.scss';
|
import './App.scss';
|
||||||
|
import MainMenu from '../MainMenu/MainMenu';
|
||||||
|
import Login from '../Login/Login';
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
auth: {
|
||||||
|
params: {
|
||||||
|
redirectUrl: 'http://localhost:8080',
|
||||||
|
responseType: 'token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auth = new AuthService(__AUTH0_CLIENT_ID__, __AUTH0_DOMAIN__, options);
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
profile: auth.getProfile()
|
||||||
|
}
|
||||||
|
auth.on('profile_updated', (newProfile) => {
|
||||||
|
this.setState({profile: newProfile})
|
||||||
|
})
|
||||||
|
this.loginButton = this.loginButton.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
auth.logout()
|
||||||
|
this.setState({
|
||||||
|
profile: auth.getProfile()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
loginButton() {
|
||||||
|
if(this.state.profile.hasOwnProperty('user_id'))
|
||||||
|
return <button className="btn-primary" onClick={this.logout.bind(this)}>Log out</button>;
|
||||||
|
else
|
||||||
|
return <button className="btn-primary" onClick={auth.login.bind(this)}>Login</button>;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>hello world</div>
|
<div>
|
||||||
|
<MainMenu profile={this.state.profile} />
|
||||||
|
{this.loginButton()}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// <Login profile={this.state.profile} />
|
||||||
|
|
||||||
export default App;
|
export default App;
|
36
src/components/Login/Login.jsx
Normal file
36
src/components/Login/Login.jsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { Component, PropTypes as T } from 'react';
|
||||||
|
import AuthService from '../../utils/AuthService'
|
||||||
|
import './Login.scss';
|
||||||
|
|
||||||
|
class Login extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.loginButton = this.loginButton.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
/* this.props.auth.logout()
|
||||||
|
this.setState({
|
||||||
|
profile: this.props.auth.getProfile()
|
||||||
|
}) */
|
||||||
|
}
|
||||||
|
|
||||||
|
loginButton() {
|
||||||
|
if(this.props.profile.hasOwnProperty('user_id'))
|
||||||
|
return <button className="btn-primary" onClick={this.logout.bind(this)}>Log out</button>;
|
||||||
|
else
|
||||||
|
return <button className="btn-primary" onClick={this.props.auth.login.bind(this)}>Login</button>;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>{this.loginButton()}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Login.propTypes = {
|
||||||
|
auth: T.instanceOf(AuthService)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Login;
|
0
src/components/Login/Login.scss
Normal file
0
src/components/Login/Login.scss
Normal file
12
src/components/MainMenu/MainMenu.jsx
Normal file
12
src/components/MainMenu/MainMenu.jsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import './MainMenu.scss';
|
||||||
|
|
||||||
|
class MainMenu extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>{this.props.profile.hasOwnProperty('user_id')?this.props.profile.name+' is logged in':'not logged in'}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MainMenu;
|
0
src/components/MainMenu/MainMenu.scss
Normal file
0
src/components/MainMenu/MainMenu.scss
Normal file
75
src/utils/AuthService.js
Normal file
75
src/utils/AuthService.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import { EventEmitter } from 'events'
|
||||||
|
import { isTokenExpired } from './jwtHelper'
|
||||||
|
import Auth0Lock from 'auth0-lock'
|
||||||
|
|
||||||
|
export default class AuthService extends EventEmitter {
|
||||||
|
constructor(clientId, domain, options) {
|
||||||
|
super()
|
||||||
|
// Configure Auth0
|
||||||
|
this.lock = new Auth0Lock(clientId, domain, options)
|
||||||
|
// Add callback for lock `authenticated` event
|
||||||
|
this.lock.on('authenticated', this._doAuthentication.bind(this))
|
||||||
|
// Add callback for lock `authorization_error` event
|
||||||
|
this.lock.on('authorization_error', this._authorizationError.bind(this))
|
||||||
|
// binds login functions to keep this context
|
||||||
|
this.login = this.login.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
_doAuthentication(authResult){
|
||||||
|
// Saves the user token
|
||||||
|
this.setToken(authResult.idToken)
|
||||||
|
// Async loads the user profile data
|
||||||
|
this.lock.getProfile(authResult.idToken, (error, profile) => {
|
||||||
|
if (error) {
|
||||||
|
console.log('Error loading the Profile', error)
|
||||||
|
} else {
|
||||||
|
this.setProfile(profile)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_authorizationError(error){
|
||||||
|
// Unexpected authentication error
|
||||||
|
console.log('Authentication Error', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
// Call the show method to display the widget.
|
||||||
|
this.lock.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
loggedIn(){
|
||||||
|
// Checks if there is a saved token and it's still valid
|
||||||
|
const token = this.getToken()
|
||||||
|
return !!token && !isTokenExpired(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
setProfile(profile){
|
||||||
|
// Saves profile data to localStorage
|
||||||
|
localStorage.setItem('profile', JSON.stringify(profile))
|
||||||
|
// Triggers profile_updated event to update the UI
|
||||||
|
this.emit('profile_updated', 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');
|
||||||
|
}
|
||||||
|
}
|
21
src/utils/jwtHelper.js
Normal file
21
src/utils/jwtHelper.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import decode from 'jwt-decode';
|
||||||
|
|
||||||
|
export function getTokenExpirationDate(token){
|
||||||
|
const decoded = decode(token)
|
||||||
|
if(!decoded.exp) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(0) // The 0 here is the key, which sets the date to the epoch
|
||||||
|
date.setUTCSeconds(decoded.exp)
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTokenExpired(token){
|
||||||
|
const date = getTokenExpirationDate(token)
|
||||||
|
const offsetSeconds = 0
|
||||||
|
if (date === null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !(date.valueOf() > (new Date().valueOf() + (offsetSeconds * 1000)))
|
||||||
|
}
|
|
@ -1,8 +1,25 @@
|
||||||
var path = require('path');
|
const NODE_ENV = 'development';
|
||||||
var webpack = require('webpack');
|
const dotenv = require('dotenv');
|
||||||
var autoprefixer = require('autoprefixer');
|
|
||||||
var precss = require('precss');
|
const webpack = require('webpack');
|
||||||
var HtmlWebPackPlugin = require('html-webpack-plugin');
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const autoprefixer = require('autoprefixer');
|
||||||
|
const precss = require('precss');
|
||||||
|
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
|
const dotEnvVars = dotenv.config();
|
||||||
|
const envVariables =
|
||||||
|
Object.assign({}, dotEnvVars);
|
||||||
|
const defines =
|
||||||
|
Object.keys(envVariables)
|
||||||
|
.reduce((memo, key) => {
|
||||||
|
const val = JSON.stringify(envVariables[key]);
|
||||||
|
memo[`__${key.toUpperCase()}__`] = val;
|
||||||
|
return memo;
|
||||||
|
}, {
|
||||||
|
__NODE_ENV__: JSON.stringify(NODE_ENV)
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: [
|
entry: [
|
||||||
|
@ -24,7 +41,8 @@ module.exports = {
|
||||||
filename: '../index.html'
|
filename: '../index.html'
|
||||||
}),
|
}),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.NoErrorsPlugin()
|
new webpack.NoErrorsPlugin(),
|
||||||
|
new webpack.DefinePlugin(defines)
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
var path = require('path');
|
const NODE_ENV = 'production';
|
||||||
var webpack = require('webpack');
|
const dotenv = require('dotenv');
|
||||||
var autoprefixer = require('autoprefixer');
|
|
||||||
var precss = require('precss');
|
const webpack = require('webpack');
|
||||||
var HtmlWebPackPlugin = require('html-webpack-plugin');
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const autoprefixer = require('autoprefixer');
|
||||||
|
const precss = require('precss');
|
||||||
|
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
|
const dotEnvVars = dotenv.config();
|
||||||
|
const envVariables =
|
||||||
|
Object.assign({}, dotEnvVars);
|
||||||
|
const defines =
|
||||||
|
Object.keys(envVariables)
|
||||||
|
.reduce((memo, key) => {
|
||||||
|
const val = JSON.stringify(envVariables[key]);
|
||||||
|
memo[`__${key.toUpperCase()}__`] = val;
|
||||||
|
return memo;
|
||||||
|
}, {
|
||||||
|
__NODE_ENV__: JSON.stringify(NODE_ENV)
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'cheap-module-source-map',
|
devtool: 'cheap-module-source-map',
|
||||||
|
@ -35,7 +52,8 @@ module.exports = {
|
||||||
warnings: false
|
warnings: false
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
new webpack.NoErrorsPlugin()
|
new webpack.NoErrorsPlugin(),
|
||||||
|
new webpack.DefinePlugin(defines)
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
|
|
Loading…
Reference in a new issue