我正在尝试实现Horizon Server(Express.js + RethinkDB)和React.js Horizon Client(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);
Horizon Container:
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);
答案 0 :(得分:0)
如果我把容器放在后面,它似乎正在工作。
仪表板中的代码:
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);
}