在 Docker 中使用 React 和 Nginx 授权 Spotify
Posted
技术标签:
【中文标题】在 Docker 中使用 React 和 Nginx 授权 Spotify【英文标题】:Authorize Spotify using React and Nginx in Docker 【发布时间】:2019-08-05 13:25:48 【问题描述】:我正在构建具有以下结构的 dockerized REST API
应用程序:
../
web/
nginx/
dev.conf
Dockerfile-dev
client/
build/
conf/
Dockerfile-dev
node_modules/
package_json
public/
src/
App.jsx
components/
SpotifyRedirect.jsx
spotify-client/
Dockerfile-dev
node_modules
package-lock.json
package.json
authorization_code/
app.js
注意:在这个项目中,用户需要经过两个授权/认证过程:
-
一个与我的应用程序,它生成一个原生的
token
(这个已经处理
已经)
另一个Spotify
(需要redirect URI
,并为其API访问提供自己的token
)
2a) 所以,在localhost
,在localhost/auth/register
或localhost/auth/login
提交之后,我会得到Spotify
redirect URI
(http://localhost:8888
),带我到这个页面:
2b) 然后,点击登录按钮,系统会要求我将我的应用与 Spotify 连接,如下所示:
最后一个OK
在那里我将获得许可并交给我一个token
,我可以在我的React
客户端上保存甚至刷新它。
本项目的构建块摘自本教程:
using-spotifys-awesome-api-with-react
但是,我已经配置了一个React
client
,除了这个授权过程之外,它还有其他用途。
以下是尝试集成这两个服务的相关代码:更通用的client
和spotify-client
。
相关代码:
所以我的第一个尝试是为spotify-client
创建一个特定的服务,在client
服务下面,将其暴露给端口8888,如下所示:
docker-compose-dev.yml
nginx:
build:
context: ./services/nginx
dockerfile: Dockerfile-dev
restart: always
ports:
- 80:80
depends_on:
- web
- client
- spotify-client
client:
build:
context: ./services/client
dockerfile: Dockerfile-dev
volumes:
- './services/client:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- 3007:3000
environment:
- NODE_ENV=development
- REACT_APP_WEB_SERVICE_URL=$REACT_APP_WEB_SERVICE_URL
depends_on:
- web
spotify-client: // NEW
build:
context: ./services/spotify-client
dockerfile: Dockerfile-dev
volumes:
- './services/spotify-client:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- 3000:8888
- 8888:3000
environment:
- NODE_ENV=development
- REACT_APP_WEB_SERVICE_URL=$REACT_APP_WEB_SERVICE_URL
depends_on:
- web
- client
然后,我将每个节点进程设置为自己的Dockerfile
,如下所示:
客户端/Dockerfile-dev
# base image
FROM node:11.6.0-alpine
# set working directory
WORKDIR /usr/src/app
# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts@2.1.2 -g --silent
# start app
CMD ["npm", "start"]
和:
spotify-client/Dockerfile-dev // 新
根据Spotify
网络文档的要求,运行不同的进程:
# base image
FROM node:11.6.0-alpine
# set working directory
WORKDIR /usr/src/app/authorization_code
# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts@2.1.2 -g --silent
# start app <-- NOT npm start
CMD ["node", "app.js"]
我的反向代理,我试过了:
nginx/dev.conf
server
listen 80;
listen 8888; // NEW
location /
proxy_pass http://client:3000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
location /auth // <-- app authorization, not Spotify's
proxy_pass http://web:5000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
在我的前端,我为我的重定向链接创建了一个component
:
client/src/components/SpofityRedirect.jsx
import React, Component from 'react';
class SpotifyRedirect extends Component
render()
return (
<div className='SpotifyRedirect'>
<a href='http://localhost:8888'> Log in with Spotify </a>
</div>
);
export default SpotifyRedirect;
这里我在“/”处显示这个重定向链接。
client/src/App.jsx
import SpotifyRedirect from './components/SpotifyRedirect';
(...)
<Switch
<Route exact path='/' render=() => (
<SpotifyRedirect/>
) />
(...)
</Switch>
更多:
spotify-client/authorization_code/app.js
(这是Spofity
提供的,我只插入了http://localhost:3000
)
var express = require('express'); // Express web server framework
var request = require('request'); // "Request" library
var cors = require('cors');
var querystring = require('querystring');
var cookieParser = require('cookie-parser');
var client_id = 'is'; // Your client id
var client_secret = 'secret'; // Your secret
var redirect_uri = 'http://localhost:8888'; // Your redirect uri
/**
* Generates a random string containing numbers and letters
* @param number length The length of the string
* @return string The generated string
*/
var generateRandomString = function(length)
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
;
var stateKey = 'spotify_auth_state';
var app = express();
app.use(express.static(__dirname + '/public'))
.use(cors())
.use(cookieParser());
app.get('/login', function(req, res)
var state = generateRandomString(16);
res.cookie(stateKey, state);
// your application requests authorization
var scope = 'user-read-private user-read-email user-read-playback-state playlist-modify-public playlist-modify-private';
res.redirect('https://accounts.spotify.com/authorize?' +
querystring.stringify(
response_type: 'code',
client_id: client_id,
scope: scope,
redirect_uri: redirect_uri,
state: state
));
);
app.get('/callback', function(req, res)
// your application requests refresh and access tokens
// after checking the state parameter
var code = req.query.code || null;
var state = req.query.state || null;
var storedState = req.cookies ? req.cookies[stateKey] : null;
if (state === null || state !== storedState)
res.redirect('/#' +
querystring.stringify(
error: 'state_mismatch'
));
else
res.clearCookie(stateKey);
var authOptions =
url: 'https://accounts.spotify.com/api/token',
form:
code: code,
redirect_uri: redirect_uri,
grant_type: 'authorization_code'
,
headers:
'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
,
json: true
;
request.post(authOptions, function(error, response, body)
if (!error && response.statusCode === 200)
var access_token = body.access_token,
refresh_token = body.refresh_token;
var options =
url: 'https://api.spotify.com/v1/me',
headers: 'Authorization': 'Bearer ' + access_token ,
json: true
;
// use the access token to access the Spotify Web API
request.get(options, function(error, response, body)
console.log(body);
);
// we can also pass the token to the browser to make requests from there
res.redirect('http://localhost:3000/#' + //NEW
querystring.stringify(
access_token: access_token,
refresh_token: refresh_token
));
else
res.redirect('/#' +
querystring.stringify(
error: 'invalid_token'
));
);
);
app.get('/refresh_token', function(req, res)
// requesting access token from refresh token
var refresh_token = req.query.refresh_token;
var authOptions =
url: 'https://accounts.spotify.com/api/token',
headers: 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) ,
form:
grant_type: 'refresh_token',
refresh_token: refresh_token
,
json: true
;
request.post(authOptions, function(error, response, body)
if (!error && response.statusCode === 200)
var access_token = body.access_token;
res.send(
'access_token': access_token
);
);
);
console.log('Listening on 8888');
app.listen(8888);
______
Docker
命令行服务:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e9870a7412c dev3_nginx "nginx -g 'daemon of…" 9 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp dev3_nginx_1
e6bc5bbff630 dev3_spotify-client "node app.js" 26 minutes ago Up 26 minutes 0.0.0.0:3000->8888/tcp dev3_spotify-auth-server_1
a6b9e84953a3 dev3_client "npm start" 25 hours "/start.sh" 25 hours ago Up 25 hours 80/tcp, 0.0.0.0:3008->8080/tcp
16fb623ca2b3 dev3_web "/usr/src/app/entryp…" 25 hours
最后,在构建之前,我运行:
$ export REACT_APP_WEB_SERVICE_URL=http://localhost
到目前为止,通过配置 aboce,当我点击 Log in with Soptify 时,我得到:
问题:
如何将上述配置与我的nginx reverse proxy
一起使用,以便:
-
为位置 / 提供我的
Spotify's
重定向 uri http://localhost:8888 的链接
使用 Spotify 授权应用程序
授权完成后返回位置 '/'?
【问题讨论】:
【参考方案1】:问题:8888端口没有容器监听,可以直接在8888端口发布spotify-client:8888
(不用nginx)。更新docker-compose-dev.yml
:
spotify-client:
ports:
- 8888:8888
如果你真的需要 nginx,那么你将需要使用 nginx 配置 + 你还需要在 8888 端口上发布 nginx。 nginx/dev.conf
例子:
server
listen 80;
location /
proxy_pass http://client:3000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
location /auth
proxy_pass http://web:5000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
# reverse proxy on the port 8888 for spotify-client
server
listen 8888;
location /
proxy_pass http://<spotify-client service/ip>:<port>/;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
docker-compose-dev.yml
和 nginx 发布的端口:
nginx:
ports:
- 80:80
- 8888:8888
一般情况下需要正确配置nginx:8888
->spotify-client:port
。
恕我直言:您根本不需要spotify-client
服务。只需在您的应用中使用implicit flow 即可获取 Spotify 令牌。它是 React/Angular(浏览器 JS 代码)更好的选择。请记住,此流程中不存在刷新令牌,因此您还需要实现静默刷新。
【讨论】:
谢谢。是的,我真的需要 nginx。您能否扩展您的答案以包含nginx
publishing?
@data_garden nginx.conf 示例包括
谢谢! nginx 和 spotify-client 都分配到了 8888 端口?我不会为 nginx 获得 Bind for 0.0.0.0:8888 failed: port is already allocated
吗?
另外,当我重建它时,我得到:nginx_1 | nginx: [emerg] "events" directive is not allowed here in /etc/nginx/conf.d/dev.conf:1
我给了你 2 个选项:1.) 没有反向代理,所以 spotify-client 在 8888 上发布 2.) 有反向代理,nginx 在 8888 上发布。不要期望完全复制/粘贴溶液。您仍然可能需要根据需要对其进行自定义。我已经更新了答案 - 现在有 dev.conf,而不是 nginx.conf【参考方案2】:
当您决定使用 nginx 时,您需要编辑配置并在端口 8888 上发布 nginx。
【讨论】:
以上是关于在 Docker 中使用 React 和 Nginx 授权 Spotify的主要内容,如果未能解决你的问题,请参考以下文章
使用 Nginx 和 Docker 部署 React 和 Django