mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
feat: add support for username/password login
This commit is contained in:
parent
91b8f15364
commit
63091184d3
@ -4,8 +4,10 @@ import { Card, CardTitle, CardText } from 'react-mdl';
|
|||||||
import Modal from 'react-modal';
|
import Modal from 'react-modal';
|
||||||
import AuthenticationSimpleComponent from './authentication-simple-component';
|
import AuthenticationSimpleComponent from './authentication-simple-component';
|
||||||
import AuthenticationCustomComponent from './authentication-custom-component';
|
import AuthenticationCustomComponent from './authentication-custom-component';
|
||||||
|
import AuthenticationPasswordComponent from './authentication-password-component';
|
||||||
|
|
||||||
const SIMPLE_TYPE = 'unsecure';
|
const SIMPLE_TYPE = 'unsecure';
|
||||||
|
const PASSWORD_TYPE = 'password';
|
||||||
|
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
overlay: {
|
overlay: {
|
||||||
@ -34,7 +36,9 @@ class AuthComponent extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
unsecureLogin: PropTypes.func.isRequired,
|
unsecureLogin: PropTypes.func.isRequired,
|
||||||
|
passwordLogin: PropTypes.func.isRequired,
|
||||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
fetchFeatureToggles: PropTypes.func.isRequired,
|
||||||
|
fetchUIConfig: PropTypes.func.isRequired,
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,7 +47,17 @@ class AuthComponent extends React.Component {
|
|||||||
if (!authDetails) return null;
|
if (!authDetails) return null;
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (authDetails.type === SIMPLE_TYPE) {
|
if (authDetails.type === PASSWORD_TYPE) {
|
||||||
|
content = (
|
||||||
|
<AuthenticationPasswordComponent
|
||||||
|
passwordLogin={this.props.passwordLogin}
|
||||||
|
authDetails={authDetails}
|
||||||
|
fetchFeatureToggles={this.props.fetchFeatureToggles}
|
||||||
|
fetchUIConfig={this.props.fetchUIConfig}
|
||||||
|
history={this.props.history}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (authDetails.type === SIMPLE_TYPE) {
|
||||||
content = (
|
content = (
|
||||||
<AuthenticationSimpleComponent
|
<AuthenticationSimpleComponent
|
||||||
unsecureLogin={this.props.unsecureLogin}
|
unsecureLogin={this.props.unsecureLogin}
|
||||||
@ -66,7 +80,7 @@ class AuthComponent extends React.Component {
|
|||||||
background: 'rgb(96, 125, 139)',
|
background: 'rgb(96, 125, 139)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Action required!
|
Action Required
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardText>{content}</CardText>
|
<CardText>{content}</CardText>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import AuthenticationComponent from './authentication-component';
|
import AuthenticationComponent from './authentication-component';
|
||||||
import { unsecureLogin } from '../../store/user/actions';
|
import { unsecureLogin, passwordLogin } from '../../store/user/actions';
|
||||||
import { fetchFeatureToggles } from '../../store/feature-actions';
|
import { fetchFeatureToggles } from '../../store/feature-actions';
|
||||||
|
import { fetchUIConfig } from '../../store/ui-config/actions';
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
unsecureLogin,
|
unsecureLogin,
|
||||||
|
passwordLogin,
|
||||||
fetchFeatureToggles,
|
fetchFeatureToggles,
|
||||||
|
fetchUIConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { CardActions, Button, Textfield } from 'react-mdl';
|
||||||
|
|
||||||
|
class EnterpriseAuthenticationComponent extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
authDetails: PropTypes.object.isRequired,
|
||||||
|
passwordLogin: PropTypes.func.isRequired,
|
||||||
|
fetchFeatureToggles: PropTypes.func.isRequired,
|
||||||
|
fetchUIConfig: PropTypes.func.isRequired,
|
||||||
|
history: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = async evt => {
|
||||||
|
evt.preventDefault();
|
||||||
|
const { username, password } = this.state;
|
||||||
|
|
||||||
|
if (!username) {
|
||||||
|
this.setState({ usernameError: 'This is a required field' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!password) {
|
||||||
|
this.setState({ passwordError: 'This is a required field' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const user = { username, password };
|
||||||
|
const path = evt.target.action;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.props.passwordLogin(path, user);
|
||||||
|
await this.props.fetchFeatureToggles();
|
||||||
|
await this.props.fetchUIConfig();
|
||||||
|
this.props.history.push(`/`);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.statusCode === 404) {
|
||||||
|
this.setState({ error: 'User not found', password: '' });
|
||||||
|
} else if (error.statusCode === 400) {
|
||||||
|
this.setState({ error: 'Wrong password', password: '' });
|
||||||
|
} else {
|
||||||
|
this.setState({ error: 'Could not sign in at the moment.' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const authDetails = this.props.authDetails;
|
||||||
|
const { username, usernameError, password, passwordError, error } = this.state;
|
||||||
|
return (
|
||||||
|
<form onSubmit={this.handleSubmit} action={authDetails.path}>
|
||||||
|
<p>{authDetails.message}</p>
|
||||||
|
<p style={{ color: 'red' }}>{error}</p>
|
||||||
|
<Textfield
|
||||||
|
label="Username or email"
|
||||||
|
floatingLabel
|
||||||
|
name="username"
|
||||||
|
type="string"
|
||||||
|
onChange={evt => this.setState({ username: evt.target.value })}
|
||||||
|
value={username}
|
||||||
|
error={usernameError}
|
||||||
|
/>
|
||||||
|
<Textfield
|
||||||
|
label="Password"
|
||||||
|
onChange={evt => this.setState({ password: evt.target.value })}
|
||||||
|
floatingLabel
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
error={passwordError}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<CardActions style={{ textAlign: 'center' }}>
|
||||||
|
<Button raised colored>
|
||||||
|
Sign in
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EnterpriseAuthenticationComponent;
|
@ -8,9 +8,10 @@ function extractLegacyMsg(body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ServiceError extends Error {
|
class ServiceError extends Error {
|
||||||
constructor() {
|
constructor(statusCode = 500) {
|
||||||
super(defaultErrorMessage);
|
super(defaultErrorMessage);
|
||||||
this.name = 'ServiceError';
|
this.name = 'ServiceError';
|
||||||
|
this.statusCode = statusCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ export function throwIfNotSuccess(response) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new ServiceError());
|
return Promise.reject(new ServiceError(response.status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.resolve(response);
|
return Promise.resolve(response);
|
||||||
|
@ -20,8 +20,18 @@ function unsecureLogin(path, user) {
|
|||||||
.then(response => response.json());
|
.then(response => response.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function passwordLogin(path, data) {
|
||||||
|
return fetch(path, {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
}).then(throwIfNotSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
fetchUser,
|
fetchUser,
|
||||||
unsecureLogin,
|
unsecureLogin,
|
||||||
logoutUser,
|
logoutUser,
|
||||||
|
passwordLogin,
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,14 @@ export function unsecureLogin(path, user) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function passwordLogin(path, user) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({ type: START_FETCH_USER });
|
||||||
|
|
||||||
|
return api.passwordLogin(path, user).then(json => dispatch(updateUser(json)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function logoutUser() {
|
export function logoutUser() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch({ type: USER_LOGOUT });
|
dispatch({ type: USER_LOGOUT });
|
||||||
|
@ -115,6 +115,11 @@ module.exports = {
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
},
|
},
|
||||||
|
'/auth': {
|
||||||
|
target: process.env.UNLEASH_API || 'http://localhost:4242',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
port: process.env.PORT || 3000,
|
port: process.env.PORT || 3000,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user