使用私有路由和上下文响应身份验证

Posted

技术标签:

【中文标题】使用私有路由和上下文响应身份验证【英文标题】:React authentication with private routes and context 【发布时间】:2020-02-22 01:28:53 【问题描述】:

我正在尝试使用私有路由和上下文向 React+Typescript 应用程序添加简单的身份验证。我有一个简单的登录组件,它带有一个按钮,它只是将上下文中的布尔变量authenticated 设置为true。私有路由应该检查这个 var 并重定向到登录组件,如果它不是真的,否则显示指定的组件。问题是authenticated 似乎总是错误的,我总是被重定向到登录页面。

当我调试它时,我可以看到 AuthContextProvider 中的setAuthenticated 函数在单击登录按钮时被调用。但是,如果我随后单击任何指向私有路由的链接,authenticated 总是错误的。

这是我的 App.tsx:

function App() 

  return (
    <AuthContextProvider>
      <Router>
        <Link to="/">Home</Link>
        <Link to="/projects">Projects</Link>
        <div>
          <Route path="/login" component=Login />
          <PrivateRoute path="/" exact component=Home />
          <PrivateRoute path="/projects" component=Projects />
        </div>
      </Router>
    </AuthContextProvider>
  );
 

export default App;

PrivateRoute.tsx:

interface PrivateRouteProps extends RouteProps 
    // tslint:disable-next-line:no-any
    component: any;


const PrivateRoute = (props: PrivateRouteProps) => 
    const  component: Component, ...rest  = props;

    return (
      <AuthContextConsumer>
        authContext => authContext && (

        <Route ...rest
            render= props => 
                authContext.authenticated === true  ? (
                    <Component ...props />
                ) : (
                    <Redirect to="/login" />
                )
            
        />

      )
      </AuthContextConsumer>
    );
;

export default PrivateRoute;

AuthContext.tsx:

export interface AuthContextInterface 
  authenticated: boolean,
  setAuthenticated(newAuthState: boolean):void


const ctxt = React.createContext<AuthContextInterface>(
    authenticated: false,
    setAuthenticated: () => 
  );

export class AuthContextProvider extends React.Component 
  setAuthenticated = (newAuthState:boolean) => 
    this.setState( authenticated: newAuthState );
  ;

  state = 
    authenticated: false,
    setAuthenticated: this.setAuthenticated,
  ;

  render() 
    return (
      <ctxt.Provider value=this.state>
        this.props.children
      </ctxt.Provider>
    );
  
  
export const AuthContextConsumer = ctxt.Consumer;

登录.tsx:

function Login() 

    return (
        <AuthContextConsumer>
        ( authenticated, setAuthenticated ) => (
               <div>
                    <p>Login</p>
                    <form>
                        <input type="text" placeholder="Username"/>
                       <input type="password" placeholder="Password"/>
                        <button onClick=event => 
              setAuthenticated(true);
            >Login</button>
                    </form>
                </div>
        )
        </AuthContextConsumer>
    );


export default Login;

我怀疑 AuthContextProvider 中的状态定义有问题。如果我在这里将authenticatedin 更改为 true,我会看到相反的行为,我永远不会看到登录页面。这应该是动态的吗?

【问题讨论】:

【参考方案1】:

或者,在 onClick 回调中,设置 event.preventDefault() 使其不提交表单。

【讨论】:

【参考方案2】:

问题原来是每次按下登录按钮时应用都在重新加载,因此丢失了 AuthContext 中的状态。

原因是在我的登录组件中,我在表单中有一个按钮,它会自动提交表单并重新加载页面。

解决办法是要么去掉表单标签,要么在按钮中指定属性type="button"

【讨论】:

以上是关于使用私有路由和上下文响应身份验证的主要内容,如果未能解决你的问题,请参考以下文章

从cookie异步加载身份验证令牌时,React react-router-dom私有路由不起作用

使用 redux 保护的路由和身份验证反应路由器 v4

我的身份验证令牌拦截器不拦截新路由的请求/响应

如何响应最近的私有 API 更改执行未经身份验证的 Instagram 网络抓取?

使用 Spring Security 自定义客户端身份验证的 OAuth2 错误响应

反应路由器经过身份验证的路由问题