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 AuthenticationSimpleComponent from './authentication-simple-component';
|
||||
import AuthenticationCustomComponent from './authentication-custom-component';
|
||||
import AuthenticationPasswordComponent from './authentication-password-component';
|
||||
|
||||
const SIMPLE_TYPE = 'unsecure';
|
||||
const PASSWORD_TYPE = 'password';
|
||||
|
||||
const customStyles = {
|
||||
overlay: {
|
||||
@ -34,7 +36,9 @@ class AuthComponent extends React.Component {
|
||||
static propTypes = {
|
||||
user: PropTypes.object.isRequired,
|
||||
unsecureLogin: PropTypes.func.isRequired,
|
||||
passwordLogin: PropTypes.func.isRequired,
|
||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
||||
fetchUIConfig: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
@ -43,7 +47,17 @@ class AuthComponent extends React.Component {
|
||||
if (!authDetails) return null;
|
||||
|
||||
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 = (
|
||||
<AuthenticationSimpleComponent
|
||||
unsecureLogin={this.props.unsecureLogin}
|
||||
@ -66,7 +80,7 @@ class AuthComponent extends React.Component {
|
||||
background: 'rgb(96, 125, 139)',
|
||||
}}
|
||||
>
|
||||
Action required!
|
||||
Action Required
|
||||
</CardTitle>
|
||||
<CardText>{content}</CardText>
|
||||
</Card>
|
||||
|
@ -1,11 +1,14 @@
|
||||
import { connect } from 'react-redux';
|
||||
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 { fetchUIConfig } from '../../store/ui-config/actions';
|
||||
|
||||
const mapDispatchToProps = {
|
||||
unsecureLogin,
|
||||
passwordLogin,
|
||||
fetchFeatureToggles,
|
||||
fetchUIConfig,
|
||||
};
|
||||
|
||||
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 {
|
||||
constructor() {
|
||||
constructor(statusCode = 500) {
|
||||
super(defaultErrorMessage);
|
||||
this.name = 'ServiceError';
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +53,7 @@ export function throwIfNotSuccess(response) {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(new ServiceError());
|
||||
return Promise.reject(new ServiceError(response.status));
|
||||
}
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
|
@ -20,8 +20,18 @@ function unsecureLogin(path, user) {
|
||||
.then(response => response.json());
|
||||
}
|
||||
|
||||
function passwordLogin(path, data) {
|
||||
return fetch(path, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers,
|
||||
body: JSON.stringify(data),
|
||||
}).then(throwIfNotSuccess);
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchUser,
|
||||
unsecureLogin,
|
||||
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() {
|
||||
return dispatch => {
|
||||
dispatch({ type: USER_LOGOUT });
|
||||
|
@ -115,6 +115,11 @@ module.exports = {
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
'/auth': {
|
||||
target: process.env.UNLEASH_API || 'http://localhost:4242',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
port: process.env.PORT || 3000,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user