【问题标题】:"ReplyError: ERR unkown command 'json.set' ? Using redis rejson, google oauth“ReplyError: ERR unkown command 'json.set' ? 使用 redis rejson, google oauth
【发布时间】:2020-05-28 02:47:00
【问题描述】:

使用 NodeJS express 服务器通过服务器端的 OpenID 协议处理 GOOGLE oauth,我试图让回调在 google 使用 auth code + 在查询字符串中将用户重定向到 API 后运行此清单。

  1. 只允许具有特殊学校域的电子邮件通过(这是一个学校项目)。
  2. 换取包含Auth Token、Refresh Token等的Token Object
  3. 通过 cookie 存储身份验证令牌
  4. 通过 redis 缓存将整个令牌对象存储在 JSON 对象中...这就是我被抓到的地方。 (使用 redis 模块 REJSON.REJSON,因为可以将数据库中的用户数据添加到内存中的对象中以用于 CACHING USER DATA...)
  5. 逻辑中的下一步包括检查用户是否存在于 mongodb 中,如果不存在则在 mongodb 中创建用户,重定向到浏览器,携带 cookie,使用身份验证令牌检查 redis 缓存以维护持久会话...最终将通过以下方式确保安全哈希、httpOnly、https 等...

希望这能让您了解我的逻辑,但这似乎是一个 REDIS 或 REDIS 相关模块问题。

为了使用 Redis REJSON 模块,我正在运行一个 redis-redisjson docker 镜像,该镜像暴露于 6379 端口,而 express 服务器(在 4000 端口上运行)将成为 redis 缓存服务器的客户端...

Node 模块 Redis-rejson 允许将 redisJSON 命令映射到对 javascript 友好的名称。 而 Node 模块 Redis 是 node 的 redis 客户端库。

//This is a minimalist web-framework for NodeJS
var express = require("express");

//axios - handles HTTP requests
const axios = require("axios");

//redis - use for caching
//rejson - store JSON via redis
const redis = require("redis"),
      rejson = require("redis-rejson");
      rejson(redis);

//set ports
const PORT = process.env.PORT || 4000;
const REDIS_PORT = process.env.PORT || 6379;

const client = redis.createClient(REDIS_PORT);

// Init Express app 
var app = express();

  //callback route from google

 app.get("/signin/callback", (req, res, next) => {
    //declare vars from query string api return for later use
    //console.log(req.query);
    let hd = req.query.hd;
    let authCode = req.query.code;

    //Only allow GUHSD email domains
    if(hd !== 'guhsd.net') {
        console.log('you are shall not pass')
        // The return is for stopping execution of controller
        return res.redirect(301, 'http://localhost:3000/?error=invalid_domain');
    } 

    //GET client_id and client_secret FROM JSON

     //Make POST REQ to exchange AuthCode for JSON token object
     axios.post('https://oauth2.googleapis.com/token', {
        client_id: '<taken out as to not expose>',
        client_secret: '<taken out as to not expose>',
        code: authCode,
        grant_type: 'authorization_code',
        redirect_uri: 'http://localhost:4000/signin/callback'
        })
        .then((response) => {
            console.log('Your token must to be here');

            // Logic after exchange 
            //1. Start Sessions - Client HTTP only Cookie & Server Redis Cache
            //2. Check if ACC exists - if so redirect client :)
            //3. if ACC DOES NOT exist, create new acc!! then redirect client :)

            async function passOver() {
                console.log(response.data);
                    // example: 
               //  {
               //     access_token: 'ya29.a0AfH6SMBSm3D99XAhmlxHtYOVVm7gZT9h8Bd8I9RgpYPhK0qXQwGT4fuMWhDsqDpcTfQuIg6bvY-tFUISX4Wm2Is-jprW2sstjmD4hjc2cQh5uIYODg1Re6v80FKENDdEAinTm9kid0QaKiaRxJQHt1deap-Ik1mcy2s',   
               //     expires_in: 3599, 
               //     refresh_token: '1//06qroj95zjugXCgYIARAAGAYSNwF-L9IrzWEi6q0wDpeUVKmnPZYZjZpsMS-KVT4fY9NzHgZCUxgY8fg2J_Nil2vJpMz52y-2pyY',
               //     scope: 'openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
               //     token_type: 'Bearer',
               //     id_token: 'eyJhbGciOiJSUzI1NiIsImtpZCI6Ijk2MGE3ZThlODM0MWVkNzUyZjEyYjE4NmZhMTI5NzMxZmUwYjA0YzAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTA1MzUzMTYxMjcxODg4Mjg5NjYiLCJoZCI6Imd1aHNkLm5ldCIsImVtYWlsIjoiMzMwMjk0QGd1aHNkLm5ldCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoidEhoVEl6eWp3MHcyRFpVaVpUMmxCQSIsIm5hbWUiOiJERVZJTiBQUk9WRU5DRSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLVhTaV9oU2JsVWo0L0FBQUFBQUFBQUFJL0FBQUFBQUFBQUFBL0FNWnV1Y25HXzBwS3N0eVo3cEI0Wk0yZlpMQkNIUEU3UkEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkRFVklOIiwiZmFtaWx5X25hbWUiOiJQUk9WRU5DRSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTkwNjEwODE4LCJleHAiOjE1OTA2MTQ0MTh9.Nt2eGzCsKrUmyztqYWiZ16-1S7OCRcUFlSFvhVAy9HusYfLqp0nz3diUkuP-D_27BCtBsZCQ0JC1evPISwLX9H1hJs_GKYSD12s-ovJ8S0AzghY0M-AOuYxhGvKautusmXYfHvhfcPj7IKhPo_IXBl3x-ryOtRRrpJR6c30QPl1JUae74sAcLk8H1stLgqptrrRTgJWYdTXxJHSrZcR8RsLw2aY4GwuPGEX-AD6h51IZlNTl_6qNpaIt_7mFSUV-iF1PECAotfhKHdAryZCFRBq4XE6uJnYq3WnOVAMAEYwqT543pxarXOmLuAwhDqqewyuCXsjlbyhBys-4iEhYAg'
               //   }
               //expires_in is in seconds... cookie takes milliseconds as expires arg. 

                //send to client, store in cookie(browser's session starts)

                res.cookie(
                    "tokenResponse", `${response.data.access_token}`, {
                        maxAge: `${response.data.expires_in}`
                    }
                )

              var keyObject = JSON.stringify(response.data);
              //set redis key to user
              var user = 'user';
                //store response.data in redis cache(server's session starts)
                client.json_set(user, '.', keyObject, function (err) {
                    if (err) { throw err; }
                    console.log('Set JSON at key ' + user + '.');
                    client.json_get(user, '.access_token', function (err, value) {
                      if (err) { throw err; }
                      console.log('value of .', value); //outputs JSON
                      client.quit();
                    });
                  });
                res.json(keyObject);

                //redirect from server to frontend
              //  await res.redirect('http://localhost:3000');
             }

             //call passover
             passOver();


        })
        //if err, log & redirect user to client
        .catch((error) => {
             console.log(error.request);
             console.log(error.response.data);
            return res.redirect(301, 'http://localhost:3000/?error=google_failed_exchange');
        }); 
 });

//start the express server
app.listen(4000, () =>
console.log(`App started on port ${PORT}`)
);

module.exports = app;

我得到的错误是

                   if (err) { throw err; }
                               ^        

ReplyError: ERR unknown command 'json.set'
    at parseError (E:\docker-node-react-nginx\backend\node_modules\redis-parser\lib\parser.js:179:12)
    at parseType (E:\docker-node-react-nginx\backend\node_modules\redis-parser\lib\parser.js:302:14) {
  command: 'JSON.SET',
  args: [
    'user',
    '.',
    '{"access_token":"ya29.a0AfH6SMCSN3_0fXFexXYUqrkfhlJ5FmdkO-eqKeiXeSnRzlwD5aBDpBF7y-pXMDBY1YFqXLf-JU0mc5FXVo8nZER-6wB-hAm7qW_0w4Z3TcfoQfOT7ZXg8ZqK2DPyW8TnsZELWe9eDBYvFqM0lTWyWe3Z9ZqUXgv6Kz4","expires_in":3599,"refresh_token":"1//06FRrH2GkKtP2CgYIARAAGAYSNwF-L9IrnL1ZpMhxaiYWYuSnI7p6DG0uFIO3Vu2qt40Scio5SAlGT0mvBZ8hWvaPcJEEnjaunDw","scope":"https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImZiOGNhNWI3ZDhkOWE1YzZjNjc4ODA3MWU4NjZjNmM0MGYzZmMxZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTA1MzUzMTYxMjcxODg4Mjg5NjYiLCJoZCI6Imd1aHNkLm5ldCIsImVtYWlsIjoiMzMwMjk0QGd1aHNkLm5ldCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoiV2kwRVdlSl9fQmVsaGV1RF9SVEl6USIsIm5hbWUiOiJERVZJTiBQUk9WRU5DRSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLVhTaV9oU2JsVWo0L0FBQUFBQUFBQUFJL0FBQUFBQUFBQUFBL0FNWnV1Y25HXzBwS3N0eVo3cEI0Wk0yZlpMQkNIUEU3UkEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkRFVklOIiwiZmFtaWx5X25hbWUiOiJQUk9WRU5DRSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTkwNjI0NDIyLCJleHAiOjE1OTA2MjgwMjJ9.IyF5uB2ldLBQLu3CVMDpXf8szEK_BbR8SPrtdpJR_Y3bHklJ8e3JYGQT9AWjkcSy0I4DNUhkXiFk25HvZ06u2ekGd_adSknUVNwZe_N1IQTlMF1m-oqWbaRtnr4oxerQg_YunZDD4z_Lh5ecSDVz4X8H39uO7jrAvY1CdnZfZ4D2Je8aV1Zns5JahKhOTopPcy5sE1dSBNPqqGvUiY9h0MQHne9byUz9jMvog3YI-8-uexjC_JWsbzMFjE65ze5_cUpApYB5tUrNTjqvhiYgcimIPOXoto_VIHHEEoho5uHOkUQw_UVXleUa9vI77W1j7U7HnH-h_3C5ylx7UEDm6Q"}'
  ],
  code: 'ERR'
}
[nodemon] app crashed - waiting for file changes before starting...

【问题讨论】:

  • 如何启动redis-server?

标签: node.js redis google-oauth openid redisjson


【解决方案1】:
import Redis from 'ioredis'
const connOpts = {
  port: process.env.REDIS_PORT,
  host: process.env.REDIS_HOST
 }
const client = new Redis(connOpts)
const sets = (id, keyPaths, input) => {
  
  return client.send_command('JSON.SET', id, keyPaths, JSON.stringify(input)).then((res) => {
    return res
  }).catch((e) => {
    console.error('redis insertion error', e)
  })
}
sets("134", ".", {"access_token":"ya29"}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多