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

查看:90
本文介绍了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内的状态并将状态作为prop发送,如下所示:

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});
    }

然后在路由器下面...

and down below in the router...

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

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

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.

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

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

推荐答案

仅在state 中处理isAuthenticated 意味着用户每次刷新页面时都将未经身份验证.那不是真正的用户友好! :)

Handling isAuthenticated only in the state means the user will be unauthenticated every time he refreshes the page. That's not really user-friendly! :)

因此,登录页面应该在您的

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.

然后,您也可以在其他所有页面上都选中此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 refresh_token 之间的区别,这将有助于您理解下面的代码,但请随时跳过如果您已经很熟悉.

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

Your backend probably uses OAuth2, which is the most common authentication protocol nowadays. With OAuth2, your app makes a first request to the server containing the username and password of the user to authenticate. Once the user is authenticated, he receives 1) an access_token, which usually expires after an hour, and 2) a refresh_token, which expires after a very long time (hours, days). When the access_token expires, instead of asking the user for his username and password again, your app sends the refresh_token to the server to obtain a new access_token for this user.

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

localStorage是两者之间的最新技术.这是一个简单的键/值持久性系统,对于存储access_token及其值似乎很完美.但是,我们还需要保留其到期日期.我们可以存储名为expires的第二个键/值对,但这对我们而言将是更逻辑的处理.

localStorage is the most recent technology between both. It's a simple key/value persistence system, which seems perfect to store the access_token and its value. But we also need to persist its date of expiration. We could store a second key/value pair named expires but it would be more logic to handle on our side.

另一方面,cookies具有本机的expires属性,这正是我们所需要的! cookies是一项旧技术,并且对开发人员不太友好,因此我个人使用 js-cookie ,这是一个用于操纵cookies的小型库.它也使它看起来也像一个简单的键/值持久性系统:Cookies.set('access_token', value)然后是Cookies.get('access_token').

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的其他专业人士:他们是交叉的子域!如果您的登录应用程序是login.mycompany.com,而主应用程序是app.mycompany.com,则可以在登录应用程序上创建cookie并从主应用程序访问它.对于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()

authenticate()

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
}

AuthenticatedRoute

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天全站免登陆