Как правильно подключиться к Horizon с помощью токена, используя localStorage?
Я пытаюсь реализовать сервер Horizon (Express.js+RethinkDB) и клиент React.js Horizon (React + Material-UI). Это два отдельных приложения.
Я нашел действительно хороший пример того, как настроить пользовательские имена входа в Horizon: https://github.com/tailsu/horizon-custom-login поэтому я начал настраивать его как бэкэнд.
Я пытаюсь реализовать Horizon в данный момент, Horizon нужен session_token и я не уверен, где разместить строку подключения для Horizon, у меня есть форма входа в систему, и я получаю обратно маркер сеанса, и я сохраняю его в localStorage, но когда страница загружается localStorage кажется пустым.
Если я перезагружаю страницу, токен работает, и все кажется нормальным.
Кто-нибудь знает, как правильно с этим справиться?
Это мой текущий код:
Приборная доска:
import React from 'react';
import {Link, withRouter} from 'react-router-dom';
import axios from 'axios';
import {backendUrl, backendApiKey, apiRequestRate} from '../../config';
import {Redirect} from 'react-router';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import Typography from 'material-ui/Typography';
import AccountCircle from 'material-ui-icons/AccountCircle';
import Menu, {MenuItem} from 'material-ui/Menu';
import PropTypes from 'prop-types';
import Tabious from './tabious';
import {dashTheme} from '../../themes/dashTheme';
import Horizon from '../../horizon-container';
import LoginForm from '../login';
const _horizon = Horizon.get();
class Dashboard extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
token: localStorage.getItem('session_token')
}
}
static contextTypes = {
router: PropTypes.object
}
state = {
anchorEl: null
};
componentDidMount(){
_horizon.connect();
this.timer = setInterval(() => {
if(_horizon.hasAuthToken() == false){
console.log('why???');
}
}, 1000);
}
componentWillUnmount(){
clearInterval(this.timer);
}
handleMenu = event => {
this.setState({anchorEl: event.currentTarget});
};
handleRequestClose = () => {
this.setState({anchorEl: null});
};
handleLogOut = (props) => {
localStorage.removeItem('session_token');
Horizon.clearAuthTokens();
this.context.router.history.push("/login");
};
handleMyAcc = (event : any, value : any) => {
this.context.router.history.push(value);
};
render() {
const {anchorEl} = this.state;
const open = Boolean(anchorEl);
return (
<div>
<AppBar style={dashTheme.bar}>
<Toolbar>
<Link to="/">
<IconButton color="contrast" aria-label="Menu">
<img src="/logoico.png" alt=""/>
</IconButton>
</Link>
<Typography type="title" style={dashTheme.typo}>
Chalton PMS
</Typography>
<Tabious/>
<div>
<IconButton aria-owns={open
? 'menu-appbar'
: null} aria-haspopup="true" onClick={this.handleMenu} color="contrast">
<AccountCircle/>
</IconButton>
<Menu id="menu-appbar" anchorEl={anchorEl} anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}} transformOrigin={{
vertical: 'top',
horizontal: 'right'
}} open={open}
onClose={this.handleRequestClose}
>
<MenuItem onClick={this.handleLogOut}>Log Out</MenuItem>
<MenuItem onTouchTap={() => {
this.context.router.history.push('/myaccount')
}}>My account</MenuItem>
</Menu>
</div>
</Toolbar>
</AppBar>
{this.props.children}
</div>
);
}
}
export default withRouter(Dashboard);
Горизонт Контейнер:
import Horizon from '@horizon/client';
import {backendUrl} from './config';
console.log(localStorage.getItem('session_token'));
const _horizon = Horizon({host: backendUrl, authType: {token: localStorage.getItem('session_token'), storeLocally: true}});
export default {
get: () => _horizon,
clearAuthTokens: () => Horizon.clearAuthTokens()
}
Авторизоваться:
import React from 'react';
import {Redirect} from 'react-router';
import axios from 'axios';
import {withRouter} from 'react-router-dom';
import {MuiThemeProvider} from 'material-ui/styles';
import Paper from 'material-ui/Paper';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import PropTypes from 'prop-types';
import {ValidatorForm, TextValidator} from 'react-material-ui-form-validator';
import {loginUrl} from '../config';
import Dashboard from './dashboard/dashboard';
import {loginTheme} from '../themes/loginTheme';
class LoginForm extends React.Component {
constructor(props,context) {
super(props,context);
this.state = {
login: {
username: '',
pwd: ''
},
token: localStorage.getItem('session_token')
};
this.handleSubmit = this.handleSubmit.bind(this);
}
static contextTypes = {
router: PropTypes.object
}
handleChange(property, event) {
const login = {
...this.state.login
};
login[property] = event.target.value;
this.setState({login});
}
handleSubmit(event) {
let payload = 'username=' + this.state.login.username + '&password=' + this.state.login.pwd;
let headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
};
let self = this;
axios.post(loginUrl + '/login', payload, headers).then(function(response) {
localStorage.setItem('session_token', response.data.token);
localStorage.setItem('session_user', self.state.login.username);
self.context.router.history.push("/");
}).catch(function(error) {
self.setState({'ErrorMSG': 'These authentication details are invalid.'});
});
event.preventDefault();
}
render() {
if(this.state.token){
<Redirect to="/" />
}
return(
<div>
<MuiThemeProvider theme={loginTheme}>
<div>
<Paper style={loginTheme.paper}>
<AppBar position="static" style={loginTheme.bar}>
<Toolbar>
<IconButton color="contrast" aria-label="Menu">
<img src="/logoico.png" alt=""/>
</IconButton>
<Typography type="title" style={loginTheme.typo}>
Chalton PMS
</Typography>
</Toolbar>
</AppBar>
<ValidatorForm ref="form" onSubmit={this.handleSubmit} onError={errors => console.log(errors)}>
<TextValidator label="Username" name="username" style={loginTheme.tf} value={this.state.login.username} onChange={this.handleChange.bind(this, 'username')} validators={['required']} errorMessages={['This field is required.', 'Username is not valid.']}/>
<TextValidator label="Password" name="password" type="password" style={loginTheme.tf} value={this.state.login.pwd} onChange={this.handleChange.bind(this, 'pwd')} validators={['required']} errorMessages={['This field is required.']}/>
<p style={loginTheme.errorMSG}>{this.state.ErrorMSG}</p>
<Button raised type="submit" style={loginTheme.loginBTN} color="primary">
Login
</Button>
</ValidatorForm>
</Paper>
</div>
</MuiThemeProvider>
</div>
);
}
}
export default withRouter(LoginForm);
1 ответ
Если я оставлю контейнер позади, это, кажется, работает.
Код в панели инструментов:
componentDidMount(){
const _horizon = new Horizon({host: backendUrl, authType: {token: localStorage.getItem('session_token'), storeLocally: true}});
_horizon.connect();
console.log(_horizon.status());
this.timer = setInterval(() => {
if(_horizon.hasAuthToken() == false){
this.handleLogOut
}
}, 1000);
}