【问题标题】:http-only cookie + token : double job?http-only cookie + token:双重工作?
【发布时间】:2019-06-12 03:05:16
【问题描述】:

亲爱的,

我正在尝试了解如何使用服务器发送的仅 hhtp cookie 在客户端管理身份验证。

我不明白的是,由于前端无法访问仅HTTP cookie,那么前端如何知道用户(仍然)经过身份验证?

到目前为止,唯一的解决方案是在身份验证成功时向客户端发送令牌。并将此令牌保存在客户端创建的第二个 cookie 中。

但在我看来,我做了两次相同的工作。

1- 在服务器端管理仅 HTTP 的 cookie,尤其是过期日期 2- 在客户端也管理第二个 cookie 的到期日期。

如何避免这种情况?我想基于 HTTP only server cookie 管理客户端的身份验证。如果有服务器cookie,则继续,否则重定向到登录页面。

我在服务器端使用 node/express 并对客户端做出反应。会话存储在redis中,双方都是HTTPS使用证书。

感谢

【问题讨论】:

    标签: node.js reactjs express cookies https


    【解决方案1】:

    您不需要存储另一个 cookie。 我想您在端点上使用基于令牌的身份验证,例如。智威汤逊。然后你想想这个场景:

    1. 用户将用户名/密码发送到服务器。
    2. 检查用户凭据,如果有效,则使用令牌创建仅限 http 的 cookie
        const user = await getUser({ where: { email } });
    
        const valid = await bcrypt.compare(password, user.password);
        if (!valid) {
          throw new UserInputError('Form Arguments invalid', {
            invalidArgs: {
              'password': 'Invalid password!',
            },
          });
        }
    
        const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
        /
        res.cookie('token', token, {
          httpOnly: true,
          maxAge: 1000 * 60 * 60 * 24 * 365,
        });
    
    
    1. 编写 auth 中间件,将 userId 放到 req 中,以便将来请求访问
    const jwt = require('jsonwebtoken');
    const { AuthenticationError } = require('apollo-server');
    
    module.exports = async function(req, res, next) {
      const { token } = req.cookies;
    
      if (token) {
        try {
          const { userId } = jwt.verify(token, process.env.APP_SECRET);
    
          if (!userId) return next();
          req.userId = userId;
    
        } catch (e) {
          console.log(e);
        }
      }
    
      next();
    };
    
    1. 检查每个请求的用户 ID。如果没有userId,则用户没有登录
      if (!req.userId) {
         throw new AuthenticationError('Log in!');
       }
    
    1. 如果用户的令牌无效/过期,您将收到 AuthenticationError。抓住它并重定向到登录页面。
    2. 如果您的 UI 依赖于用户状态,您可以创建易于使用的组件(我正在使用 React)来检查它。

    用户组件:

    import { Query } from 'react-apollo';
    import gql from 'graphql-tag';
    import PropTypes from 'prop-types';
    
    const CURRENT_USER_QUERY = gql`
      query CURRENT_USER_QUERY {
        me {
          userId
          firstName
          lastName
          profilePictureUrl
        }
      }
    `;
    
    const User = props => (
      <Query {...props} query={CURRENT_USER_QUERY} fetchPolicy={'cache-first'}>
        {payload => props.children(payload)}
      </Query>
    );
    
    User.propTypes = {
      children: PropTypes.func.isRequired,
    };
    
    export default User;
    
    

    如果我们从服务器获取me对象,你知道,有一个登录的用户,所以你可以根据用户的状态进行渲染:

    import { Link } from 'react-router-dom';
    import React from 'react';
    
    <User>
      {({ loading, error, data: { me } }) => {
        if (loading || error || !me) return (
          <Button component={Link} to={'/login'}>Login</Button>
        );
        if(me) return (
          <Button component={Link} to={'/dashboard'}>Go to dashboard</Button>
        )
      }}
    </User>
    

    【讨论】:

    • 非常感谢,这正是我的想法。我要在 react 中创建一个 HOC Auth。
    • 大家好,你们有这种实现的回购吗?
    • 不幸的是我没有公开的回购。但请随时提出您的问题。
    猜你喜欢
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2022-08-20
    • 2021-06-29
    • 1970-01-01
    • 2017-05-30
    相关资源
    最近更新 更多