每个 API 请求都会创建 Express-session 新会话

时间:2021-01-16 03:39:27

标签: node.js angular cookies express-session

我正在使用 Spotify API,我正在尝试使用快速会话将用户访问令牌和刷新令牌保存到他们的会话中。我已经尝试了几乎所有我能找到的方法,但没有任何效果。

这是我的 app.js 代码,用于设置我的快速会话

var app = express();

var corsOptions = {
  origin: 'https://jq-spotify.herokuapp.com',
  credentials: true
}
//Specify that connections from localhost:4200 (the client app) are allowed
app.use(cors(corsOptions));//http://localhost:4200
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
//app.use(cookieParser());

app.use(session({
  name: 'sess-id',
  secret: 'jqSpotifySessionSecretToken',
  saveUninitialized: false,
  resave: false,
  store: new FileStore({}),
  proxy: true,
  cookie: {
    sameSite: true,
    secure: true,
    maxAge: 3600000,
    path: '/'
  }
}));
app.use('/', indexRouter);

这是我执行 API 调用的 index.js 文件。所以首先用户必须 /login,然后他被重定向到 /callback 保存会话(以及访问和刷新令牌)。之后,每当用户再次调用 API 时,express-sessions 都会创建一个新会话,并且不再保存访问/刷新令牌。

router.get('/login', function (req, res, next) {
    var scopes = 'user-read-private user-read-email user-top-read';
    res.redirect('https://accounts.spotify.com/authorize' +
        '?response_type=code' +
        '&show_dialog=true&client_id=' + my_client_id +
        (scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
        '&redirect_uri=' + encodeURIComponent(redirect_uri));
});

router.get('/callback', function (req, res, next) {
    var code = req.query.code || null;
    var error = req.query.error || null;

    if (error) {
        console.error(error);
    } else {
        //we're probably good
        const params = new URLSearchParams();
        params.append('code', code);
        params.append('redirect_uri', redirect_uri);
        params.append('grant_type', 'authorization_code');

        var headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Basic ' + Buffer.from(my_client_id + ':' + my_client_secret).toString('base64')
        };

        fetch('https://accounts.spotify.com/api/token', {
            method: 'POST',
            body: params,
            headers: headers,
            credentials: 'include',
            withCredentials: true
        }).then(response => {
            if (response.ok) {
                return response.json();
            } else {
                //Could be better to redirect to an error page, but we'll go back to the client.
                res.redirect(client_uri);
            }
        }).then(json => {
            req.session.access_token = json.access_token;
            req.session.refresh_token = json.refresh_token;
            req.session.save();
            res.redirect(client_uri);

        }).catch(err => console.error(err));
    }
});

router.get('*', function (req, res, next) {
    next();

});

router.get('/me', function (req, res, next) {
    makeAPIRequest('https://api.spotify.com/v1/me', res, req);
});


function refresh(req) {
    const params = new URLSearchParams();
    params.append('refresh_token', req.session.refresh_token);
    params.append('grant_type', 'refresh_token');

    var headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Basic ' + Buffer.from(my_client_id + ':' + my_client_secret).toString('base64')
    };

    return fetch('https://accounts.spotify.com/api/token', {
        method: 'POST',
        body: params,
        headers: headers,
        credentials: 'include',
        withCredentials: true
    }).then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw ("Error refreshing token " + req.session.refresh_token + " " + refresh_token + " " + req.session.access_token+" " + access_token);
        }
    }).then(json => {
        req.session.access_token = json.access_token;
        req.session.refresh_token = json.refresh_token;

        req.session.save();
        return Promise.resolve();

    }).catch(err => console.error(err));
}

function makeAPIRequest(url, res, req) {
    var headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ' +  req.session.access_token
    };

    fetch(url, {method: 'GET', headers: headers, credentials: 'include', withCredentials: true}).then(response => {
        if (response.ok) {
            return response.json();
        } else {
            if (response.status == 401) {
                refresh(req).then(() => {
                    return fetch(url, {method: 'GET', headers: headers, credentials: 'include', withCredentials: true}).then(response => {
                        if (response.ok) {
                            return response.json();
                        } else {
                            res.status(response.status).end();
                        }
                    });
                });
            } else {
                res.status(response.status).end();
            }
            return null;
        }
    }).then(json => {
        res.json(json);
    }).catch(err => {
        console.error(err);
    });
}

我也在 Heroku 上托管我的服务器! 我再次用尽了我在互联网上能找到的所有东西,但没有任何效果。我很感激你的帮助,我已经坚持了一个星期!谢谢!

编辑:这是我的客户端调用 API 函数的方式

private sendRequestToExpress(endpoint: string): Promise<any> {
        return this.http.get(this.expressBaseUrl + endpoint).toPromise().then((data) => {
            return data;
        });
    }

1 个答案:

答案 0 :(得分:0)

我会更改返回 Promise.resolve() 以便它会在 save() 之后执行:

}).then(json => {
    req.session.access_token = json.access_token;
    req.session.refresh_token = json.refresh_token;

    req.session.save(function(err) {
        return Promise.resolve();
    });

}).catch(err => console.error(err));