working login
This commit is contained in:
parent
cfa55f5cf1
commit
df40e5d37a
|
@ -24,6 +24,7 @@
|
|||
"babel-preset-es2015": "^6.9.0",
|
||||
"babel-preset-react": "^6.11.1",
|
||||
"css-loader": "^0.23.1",
|
||||
"dotenv": "^2.0.0",
|
||||
"file-loader": "^0.9.0",
|
||||
"html-webpack-plugin": "^2.22.0",
|
||||
"postcss": "^5.0.21",
|
||||
|
@ -36,6 +37,8 @@
|
|||
"webpack-dev-server": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"auth0-lock": "^10.0.0",
|
||||
"jwt-decode": "^2.1.0",
|
||||
"postcss": "^5.1.0",
|
||||
"react": "^15.2.1",
|
||||
"react-dom": "^15.2.1"
|
||||
|
|
|
@ -1,12 +1,54 @@
|
|||
import React, { Component } from 'react';
|
||||
import AuthService from '../../utils/AuthService'
|
||||
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 {
|
||||
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() {
|
||||
return (
|
||||
<div>hello world</div>
|
||||
<div>
|
||||
<MainMenu profile={this.state.profile} />
|
||||
{this.loginButton()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
// <Login profile={this.state.profile} />
|
||||
|
||||
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');
|
||||
var webpack = require('webpack');
|
||||
var autoprefixer = require('autoprefixer');
|
||||
var precss = require('precss');
|
||||
var HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||
const NODE_ENV = 'development';
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
const webpack = require('webpack');
|
||||
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 = {
|
||||
entry: [
|
||||
|
@ -24,7 +41,8 @@ module.exports = {
|
|||
filename: '../index.html'
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoErrorsPlugin()
|
||||
new webpack.NoErrorsPlugin(),
|
||||
new webpack.DefinePlugin(defines)
|
||||
],
|
||||
module: {
|
||||
loaders: [
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var autoprefixer = require('autoprefixer');
|
||||
var precss = require('precss');
|
||||
var HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||
const NODE_ENV = 'production';
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
const webpack = require('webpack');
|
||||
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 = {
|
||||
devtool: 'cheap-module-source-map',
|
||||
|
@ -35,7 +52,8 @@ module.exports = {
|
|||
warnings: false
|
||||
},
|
||||
}),
|
||||
new webpack.NoErrorsPlugin()
|
||||
new webpack.NoErrorsPlugin(),
|
||||
new webpack.DefinePlugin(defines)
|
||||
],
|
||||
module: {
|
||||
loaders: [
|
||||
|
|
Loading…
Reference in a new issue