Saya mencoba untuk menerapkan dikonfirmasi rute yang Bereaksi Router 4 sekarang mencegah hal ini bekerja:
<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
<Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
<Route exact path="/domains" component={DomainsIndex} />
</Route>
Kesalahan adalah:
Peringatan: Anda tidak harus menggunakan
<Rute komponen>
dan<Route anak-anak>
di rute yang sama;<Route anak-anak>
akan diabaikan
Dalam hal ini, apa cara yang benar untuk menerapkan ini?
Muncul di bereaksi-router
(v4) dokumen, itu menunjukkan sesuatu seperti
<Router>
<div>
<AuthButton/>
<ul>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path="/protected" component={Protected}/>
</div>
</Router>
Tapi isit mungkin untuk mencapai ini sementara pengelompokan sekumpulan rute yang sama?
UPDATE
Ok, setelah beberapa penelitian, saya datang dengan ini:
import React, {PropTypes} from "react"
import {Route} from "react-router-dom"
export default class AuthenticatedRoute extends React.Component {
render() {
if (!this.props.isLoggedIn) {
this.props.redirectToLogin()
return null
}
return <Route {...this.props} />
}
}
AuthenticatedRoute.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
component: PropTypes.element,
redirectToLogin: PropTypes.func.isRequired
}
Isit yang benar untuk mengirimkan sebuah aksi di render()
ini terasa salah. Itu tidak benar-benar tampak benar dengan componentDidMount
atau beberapa lainnya hook baik?
Anda're akan ingin menggunakan Mengarahkan
komponen. Ada's beberapa pendekatan yang berbeda untuk masalah ini. Berikut ini's salah satu yang saya suka, memiliki PrivateRoute komponen yang diperlukan dalam sebuah authed
prop dan kemudian membuat didasarkan pada alat peraga.
function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
Sekarang anda `Rute ini dapat terlihat seperti ini
<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />
Jika anda're masih bingung, saya menulis posting ini yang dapat membantu - Dilindungi rute dan otentikasi dengan Bereaksi Router v4
Tnx Tyler McGinnis untuk solusi. Saya membuat ide dari Tyler McGinnis ide.
const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
return (
<Route
{...rest}
render={
decisionFunc()
? trueComponent
: falseComponent
}
/>
)
}
Anda dapat menerapkan yang seperti ini
<DecisionRoute path="/signin" exact={true}
trueComponent={redirectStart}
falseComponent={SignInPage}
decisionFunc={isAuth}
/>
decisionFunc hanya sebuah fungsi yang mengembalikan nilai true atau false
const redirectStart = props => <Redirect to="/orders" />
Hanya menambahkan solusi saya untuk masalah ini.
Saya menggunakan jwt token untuk otentikasi, Sehingga jika pengguna memiliki tanda itu maka saya akan mengarahkan mereka ke halaman rumah atau lain aku akan mengarahkan mereka untuk masuk pada halaman default (yang merupakan rute ini '/'). Jadi setelah user login dan mencoba untuk akses masuk halaman url (dalam kasus saya '/') . Saya akan mengarahkan mereka ke rumah secara default('/rumah').
Dan komponen yang memiliki HOC bernama requireAuth untuk memeriksa apakah user token yang valid.jika tidak maka panggilan signout tindakan yang menghilangkan localhistory token.
import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
//and also import appropriate components
//middleware
class checkStatus extends React.Component {
render() {
if(localStorage.getItem('token')){
return (
<Fragment>
<App>
<Route path="/home" exact component={Overview} />
<Route path="/home/add" exact component={Add} />
<Route path="/signout" component={Signout} />
<Route path="/details" component={details} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
</App>
</Fragment>
)
}else{
return (
<Fragment>
<Route path="/" exact component={Signin} />
<Redirect to="/" />
</Fragment>
)
}
} }
ReactDOM.render( <Provider store={store}>
<BrowserRouter>
<Switch >
<Route path="/" exact component={checkStatus} />
<Route path="/:someParam" component={checkStatus}/>
</Switch >
</BrowserRouter> </Provider>, document.querySelector('#root')
);
menginstal bereaksi-router-dom
kemudian buat dua komponen satu untuk pengguna yang valid dan tidak valid untuk pengguna.
coba ini app.js
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';
import ValidUser from "./pages/validUser/validUser";
import InValidUser from "./pages/invalidUser/invalidUser";
const loggedin = false;
class App extends React.Component {
render() {
return (
<Router>
<div>
<Route exact path="/" render={() =>(
loggedin ? ( <Route component={ValidUser} />)
: (<Route component={InValidUser} />)
)} />
</div>
</Router>
)
}
}
export default App;
Berdasarkan jawaban dari @Tyler McGinnis. Saya membuat pendekatan yang berbeda dengan menggunakan ES6 sintaks dan bersarang rute dengan dibungkus komponen:
import React, { cloneElement, Children } from 'react'
import { Route, Redirect } from 'react-router-dom'
const PrivateRoute = ({ children, authed, ...rest }) =>
<Route
{...rest}
render={(props) => authed ?
<div>
{Children.map(children, child => cloneElement(child, { ...child.props }))}
</div>
:
<Redirect to={{ pathname: '/', state: { from: props.location } }} />}
/>
export default PrivateRoute
Dan menggunakannya:
<BrowserRouter>
<div>
<PrivateRoute path='/home' authed={auth}>
<Navigation>
<Route component={Home} path="/home" />
</Navigation>
</PrivateRoute>
<Route exact path='/' component={PublicHomePage} />
</div>
</BrowserRouter>
Aku tahu itu's sudah lama tapi aku've telah bekerja pada npm paket untuk pribadi dan umum rute.
Berikut ini's bagaimana untuk membuat pribadi rute:
<PrivateRoute exact path="/private" authed={true} redirectTo="/login" component={Title} text="This is a private route"/>
Dan anda juga dapat membuat Semua rute yang hanya unauthed pengguna dapat mengakses
<PublicRoute exact path="/public" authed={false} redirectTo="/admin" component={Title} text="This route is for unauthed users"/>
Saya harap ini membantu!
Jawaban saya Sebelumnya tidak terukur. Berikut adalah apa yang saya pikir adalah pendekatan yang baik-
Rute Anda-
<Switch>
<Route
exact path="/"
component={matchStateToProps(InitialAppState, {
routeOpen: true // no auth is needed to access this route
})} />
<Route
exact path="/profile"
component={matchStateToProps(Profile, {
routeOpen: false // can set it false or just omit this key
})} />
<Route
exact path="/login"
component={matchStateToProps(Login, {
routeOpen: true
})} />
<Route
exact path="/forgot-password"
component={matchStateToProps(ForgotPassword, {
routeOpen: true
})} />
<Route
exact path="/dashboard"
component={matchStateToProps(DashBoard)} />
</Switch>
Idenya adalah untuk menggunakan pembungkus di komponen
alat peraga yang akan kembali komponen asli jika tidak ada auth diperlukan atau sudah dikonfirmasi jika tidak akan kembali default komponen misalnya Login.
const matchStateToProps = function(Component, defaultProps) {
return (props) => {
let authRequired = true;
if (defaultProps && defaultProps.routeOpen) {
authRequired = false;
}
if (authRequired) {
// check if loginState key exists in localStorage (Your auth logic goes here)
if (window.localStorage.getItem(STORAGE_KEYS.LOGIN_STATE)) {
return <Component { ...defaultProps } />; // authenticated, good to go
} else {
return <InitialAppState { ...defaultProps } />; // not authenticated
}
}
return <Component { ...defaultProps } />; // no auth is required
};
};
Aku diimplementasikan menggunakan-
<Route path='/dashboard' render={() => (
this.state.user.isLoggedIn ?
(<Dashboard authenticate={this.authenticate} user={this.state.user} />) :
(<Redirect to="/login" />)
)} />
mengotentikasi alat peraga akan diteruskan ke komponen misalnya pendaftaran menggunakan pengguna yang keadaan dapat berubah. Lengkapi AppRoutes-
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { Redirect } from 'react-router';
import Home from '../pages/home';
import Login from '../pages/login';
import Signup from '../pages/signup';
import Dashboard from '../pages/dashboard';
import { config } from '../utils/Config';
export default class AppRoutes extends React.Component {
constructor(props) {
super(props);
// initially assuming that user is logged out
let user = {
isLoggedIn: false
}
// if user is logged in, his details can be found from local storage
try {
let userJsonString = localStorage.getItem(config.localStorageKey);
if (userJsonString) {
user = JSON.parse(userJsonString);
}
} catch (exception) {
}
// updating the state
this.state = {
user: user
};
this.authenticate = this.authenticate.bind(this);
}
// this function is called on login/logout
authenticate(user) {
this.setState({
user: user
});
// updating user's details
localStorage.setItem(config.localStorageKey, JSON.stringify(user));
}
render() {
return (
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/login' render={() => <Login authenticate={this.authenticate} />} />
<Route exact path='/signup' render={() => <Signup authenticate={this.authenticate} />} />
<Route path='/dashboard' render={() => (
this.state.user.isLoggedIn ?
(<Dashboard authenticate={this.authenticate} user={this.state.user} />) :
(<Redirect to="/login" />)
)} />
</Switch>
);
}
}
Memeriksa proyek yang lengkap di sini: https://github.com/varunon9/hello-react
Tampaknya anda ragu-ragu dalam membuat sendiri komponen dan kemudian pengiriman di render metode? Nah anda bisa menghindari kedua dengan hanya menggunakan render
metode <Rute>
komponen. Tidak perlu untuk membuat <AuthenticatedRoute>
komponen kecuali jika anda benar-benar ingin. Hal ini dapat sebagai sederhana sebagai berikut. Catatan {...routeProps}
menyebar memastikan anda terus mengirim sifat-sifat <Rute>
komponen ke komponen anak (<MyComponent>
dalam kasus ini).
<Route path='/someprivatepath' render={routeProps => {
if (!this.props.isLoggedIn) {
this.props.redirectToLogin()
return null
}
return <MyComponent {...routeProps} anotherProp={somevalue} />
} />
Lihat Bereaksi Router V4 membuat dokumentasi
Jika anda tidak ingin membuat didedikasikan komponen, maka sepertinya anda berada di jalur yang benar. Sejak Bereaksi Router V4 adalah murni deklaratif routing (ia mengatakan hal itu tepat di keterangan) saya tidak berpikir anda akan lolos dengan menempatkan kode redirect luar normal komponen siklus hidup. Melihat kode untuk Bereaksi Router itu sendiri, mereka melakukan redirect baik componentWillMount
atau componentDidMount
tergantung pada apakah atau tidak itu adalah sisi server rendering. Berikut ini adalah kode di bawah ini, yang cukup sederhana dan bisa membantu anda merasa lebih nyaman dengan yang mana untuk menempatkan anda mengarahkan logika.
import React, { PropTypes } from 'react'
/**
* The public API for updating the location programatically
* with a component.
*/
class Redirect extends React.Component {
static propTypes = {
push: PropTypes.bool,
from: PropTypes.string,
to: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
])
}
static defaultProps = {
push: false
}
static contextTypes = {
router: PropTypes.shape({
history: PropTypes.shape({
push: PropTypes.func.isRequired,
replace: PropTypes.func.isRequired
}).isRequired,
staticContext: PropTypes.object
}).isRequired
}
isStatic() {
return this.context.router && this.context.router.staticContext
}
componentWillMount() {
if (this.isStatic())
this.perform()
}
componentDidMount() {
if (!this.isStatic())
this.perform()
}
perform() {
const { history } = this.context.router
const { push, to } = this.props
if (push) {
history.push(to)
} else {
history.replace(to)
}
}
render() {
return null
}
}
export default Redirect
Heres bagaimana saya soal dengan Bereaksi dan Ketangkasan. Semoga membantu !
import * as React from 'react';
import { Route, RouteComponentProps, RouteProps, Redirect } from 'react-router';
const PrivateRoute: React.SFC<RouteProps> = ({ component: Component, ...rest }) => {
if (!Component) {
return null;
}
const isLoggedIn = true; // Add your provider here
return (
<Route
{...rest}
render={(props: RouteComponentProps<{}>) => isLoggedIn ? (<Component {...props} />) : (<Redirect to={{ pathname: '/', state: { from: props.location } }} />)}
/>
);
};
export default PrivateRoute;
<PrivateRoute component={SignIn} path="/signin" />
const Root = ({ session }) => {
const isLoggedIn = session && session.getCurrentUser
return (
<Router>
{!isLoggedIn ? (
<Switch>
<Route path="/signin" component={<Signin />} />
<Redirect to="/signin" />
</Switch>
) : (
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/something-else" component={SomethingElse} />
<Redirect to="/" />
</Switch>
)}
</Router>
)
}
Berikut ini adalah bersih sederhana dilindungi rute
const ProtectedRoute
= ({ isAllowed, ...props }) =>
isAllowed
? <Route {...props}/>
: <Redirect to="/authentificate"/>;
const _App = ({ lastTab, isTokenVerified })=>
<Switch>
<Route exact path="/authentificate" component={Login}/>
<ProtectedRoute
isAllowed={isTokenVerified}
exact
path="/secrets"
component={Secrets}/>
<ProtectedRoute
isAllowed={isTokenVerified}
exact
path="/polices"
component={Polices}/>
<ProtectedRoute
isAllowed={isTokenVerified}
exact
path="/grants" component={Grants}/>
<Redirect from="/" to={lastTab}/>
</Switch>
isTokenVerified
adalah metode panggilan untuk memeriksa otorisasi token pada dasarnya ia mengembalikan boolean.
Saya juga mencari beberapa jawaban. Di sini semua jawaban yang cukup baik, namun tidak satupun dari mereka memberikan jawaban bagaimana kita dapat menggunakannya jika pengguna mulai aplikasi setelah membukanya kembali. (Aku bermaksud untuk mengatakan menggunakan cookie bersama-sama).
Tidak perlu untuk membuat bahkan berbeda privateRoute Komponen. Di bawah ini adalah kode saya
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter, Redirect } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './stores';
import requireAuth from './components/authentication/authComponent'
import SearchComponent from './components/search/searchComponent'
import LoginComponent from './components/login/loginComponent'
import ExampleContainer from './containers/ExampleContainer'
class App extends Component {
state = {
auth: true
}
componentDidMount() {
if ( ! Cookies.get('auth')) {
this.setState({auth:false });
}
}
render() {
return (
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route exact path="/searchComponent" component={requireAuth(SearchComponent)} />
<Route exact path="/login" component={LoginComponent} />
<Route exact path="/" component={requireAuth(ExampleContainer)} />
{!this.state.auth && <Redirect push to="/login"/> }
</Switch>
</BrowserRouter>
</Provider>);
}
}
}
export default App;
Dan di sini adalah authComponent
import React from 'react';
import { withRouter } from 'react-router';
import * as Cookie from "js-cookie";
export default function requireAuth(Component) {
class AuthenticatedComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
auth: Cookie.get('auth')
}
}
componentDidMount() {
this.checkAuth();
}
checkAuth() {
const location = this.props.location;
const redirect = location.pathname + location.search;
if ( ! Cookie.get('auth')) {
this.props.history.push(`/login?redirect=${redirect}`);
}
}
render() {
return Cookie.get('auth')
? <Component { ...this.props } />
: null;
}
}
return withRouter(AuthenticatedComponent)
}
Di bawah ini saya telah menulis blog, anda bisa mendapatkan penjelasan lebih mendalam di sana juga.