React - 处理登录和身份验证的最佳方法是什么? [英] React - What is the best way to handle login and authentication?

查看:74
本文介绍了React - 处理登录和身份验证的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

刚开始使用身份验证/登录来响应和处理应用程序.它目前可以工作,但感觉被黑客攻击了.现在我的 isAuthenticated 状态位于我的 routes.js 中,如下所示:

New to react and working on an application with authentication/logging in. It currently works but feels hacked together. Right now I have my isAuthenticated state located in my routes.js like so:

class Routes extends Component {

    constructor(props) {
        super(props);

        this.state = {
            isAuthenticated: false,
         }
     }

在我的登录页面上,我需要知道用户何时通过身份验证以将他们重定向到 home 页面.允许访问和操作此 isAuthenticated 状态的最佳设计模式是什么?我目前的设置方式是我有一个函数可以在 routes.js 中设置状态并将状态作为道具发送,如下所示:

On my login page, I need to know when a user is authenticated to redirect them to the home page. What is the best design pattern to allow access and manipulation of this isAuthenticated state? How I currently have it set up is I have a function that sets the state inside the routes.js and sends the state as a prop like so:

 setAuthenticated = (isAuthenticated) => {
        this.setState({isAuthenticated});
    }

在路由器下面...

<Route path="/" exact component={() =>
                            <div>
                                <Login
                                    isAuthenticated={this.state.isAuthenticated}
                                    setAuthenticated={this.setAuthenticated}
                            </div>
                        } />

}/>

Yes, I understand this is bad design because this is changing props values which are supposed to be immutable. This is also bad because when I change this value in my login.js it causes multiple unnecessary re-renders. Should I be declaring isAuthenticated as some type of global variable? I am not using any state management by the way.

是的,我知道这是一个糟糕的设计,因为这改变了本应不可变的 props 值.这也很糟糕,因为当我在 login.js 中更改此值时,它会导致多次不必要的重新渲染.我应该将 isAuthenticated 声明为某种类型的全局变量吗?顺便说一下,我没有使用任何状态管理.

I am setting isAuthenticated based on a response from my server which confirms correct login/password combination.

我正在根据服务器的响应设置 isAuthenticated,确认正确的登录名/密码组合.

解决方案

推荐答案

Handling isAuthenticated 仅在 state 表示用户将未经身份验证每次他刷新页面.这不是真正的用户友好!:)

So instead, the Login page should store an access_token (coming from your backend) in the cookies or localStorage of the browser. An access_token proves the user is authenticated and also verifies his identity. You will usually pass this access_token to every next requests to your server, to check if this user is allowed to access the data he's requesting, or allowed to create, edit and delete the things he's trying to create, edit and delete.

因此,登录页面应该cookieslocalStorage 浏览器.access_token 证明用户已通过身份验证并验证其身份.您通常会将这个 access_token 传递给您服务器的每个下一个请求,以检查该用户是否被允许访问他请求的数据,或者是否允许创建、编辑和删除他试图创建的内容,编辑和删除.

Then you can check this access_token on every other pages as well and redirect the user to the Login page if he's not authenticated anymore.

然后您也可以在所有其他页面上检查此 access_token,如果用户不再通过身份验证,则将用户重定向到登录页面.

A brief aside on the difference between access_token and refresh_tokenthis will help you understand the code bellow, but feel free to skip ahead if you are already familiar with it.

简要介绍 access_tokenrefresh_token 之间的区别 – 这将有助于您理解代码如下,但如果您已经熟悉它,请随意跳过.

您的后端可能使用 OAuth2,这是当今最常见的身份验证协议.使用 OAuth2,您的应用向服务器发出第一个请求,其中包含用户的用户名和密码以进行身份​​验证.用户通过身份验证后,他会收到 1) access_token,通常会在一个小时后过期,以及 2) 一个 refresh_token,它会在很长时间后过期(几小时,天).当 access_token 过期时,您的应用不会再次询问用户的用户名和密码,而是将 refresh_token 发送到服务器以获取新的 access_token> 对于这个用户.

A brief aside on the differences between cookies and localStoragefeel free to skip it too!

简要介绍 cookieslocalStorage 之间的区别 – 可以跳过它也是!

localStorage 是两者之间的最新技术.这是一个简单的键/值持久性系统,它似乎非常适合存储 access_token 及其值.但是我们也需要坚持它的过期日期.我们可以存储名为 expires 的第二个键/值对,但我们这边处理起来会更合乎逻辑.

On the other hand, cookies have a native expires property, which is exactly what we need! cookies are an old technology and are not very developer-friendly, so I personally use js-cookie, which is a small library to manipulate cookies. It makes it look like a simple key/value persistence system too: Cookies.set('access_token', value) then Cookies.get('access_token').

另一方面,cookies 有一个原生的 expires 属性,这正是我们所需要的!cookies 是一项老技术,对开发者不是很友好,所以我个人使用 js-cookie,这是一个操作cookies的小型库.它也让它看起来像一个简单的键/值持久化系统:Cookies.set('access_token', value) 然后 Cookies.get('access_token').>

cookies 的其他专业人士:它们是跨子域!如果您的登录应用程序是 login.mycompany.com 而您的主应用程序是 app.mycompany.com,那么您可以在登录应用程序并从主应用程序访问它.LocalStorage 无法做到这一点.

Other pro for the cookies: they are cross subdomains! If your Login app is login.mycompany.com and your Main app is app.mycompany.com, then you can create a cookie on the Login app and access it from the Main app. This is not possible with LocalStorage.

以下是我用于身份验证的一些方法和特殊的 React 组件:

Here are some of the methods and special React components I use for authentication:

import Cookies from 'js-cookie'

export const getAccessToken = () => Cookies.get('access_token')
export const getRefreshToken = () => Cookies.get('refresh_token')
export const isAuthenticated = () => !!getAccessToken()

认证()

export const authenticate = async () => {
  if (getRefreshToken()) {
    try {
      const tokens = await refreshTokens() // call an API, returns tokens

      const expires = (tokens.expires_in || 60 * 60) * 1000
      const inOneHour = new Date(new Date().getTime() + expires)

      // you will have the exact same setters in your Login page/app too
      Cookies.set('access_token', tokens.access_token, { expires: inOneHour })
      Cookies.set('refresh_token', tokens.refresh_token)

      return true
    } catch (error) {
      redirectToLogin()
      return false
    }
  }

  redirectToLogin()
  return false
}

redirectToLogin()

const redirectToLogin = () => {
  window.location.replace(
    `${getConfig().LOGIN_URL}?next=${window.location.href}`
  )
  // or history.push('/login') if your Login page is inside the same app
}

认证路由

export const AuthenticatedRoute = ({
  component: Component,
  exact,
  path,
}) => (
  <Route
    exact={exact}
    path={path}
    render={props =>
      isAuthenticated() ? (
        <Component {...props} />
      ) : (
        <AuthenticateBeforeRender render={() => <Component {...props} />} />
      )
    }
  />
)

AuthenticateBeforeRender

class AuthenticateBeforeRender extends Component {
  state = {
    isAuthenticated: false,
  }

  componentDidMount() {
    authenticate().then(isAuthenticated => {
      this.setState({ isAuthenticated })
    })
  }

  render() {
    return this.state.isAuthenticated ? this.props.render() : null
  }
}

这篇关于React - 处理登录和身份验证的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆