diff --git a/Dockerfile b/Dockerfile index 47617ba..c1c3cfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,55 @@ -FROM golang:1.20 +# 阶段1:构建(使用轻量级的 Alpine 版本作为构建阶段) +## 2.1 前端构建 +FROM node:16-alpine AS frontend-builder + +# 设置工作目录 WORKDIR /app/Open-OAuth2Playground -COPY ./go.mod . -COPY ./go.sum . +# 复制前端项目并构建 +COPY ./front-standalone /app/Open-OAuth2Playground/front-standalone +RUN cd front-standalone && npm install && npm run build + +FROM golang:1.20-alpine AS backend-builder + +# 设置工作目录 +WORKDIR /app/Open-OAuth2Playground + +# 复制依赖文件并安装依赖 +COPY go.mod . +COPY go.sum . ENV GOPROXY=https://goproxy.cn,direct RUN go mod download + +# 复制源代码并编译 COPY . . -RUN go build -o OAuth2Playground . +RUN CGO_ENABLED=0 go build -o oauth2playground . + + +# 阶段2:运行 +FROM alpine:latest + +# 设置工作目录并复制二进制文件 +WORKDIR /app + +ENV PATH_ROOT=/app + +# 安装必要的运行 / 调试工具 +RUN apk update && \ + apk add --no-cache sudo bash lsof jq curl iproute2 net-tools procps ca-certificates git iputils + +COPY --from=frontend-builder /app/Open-OAuth2Playground/front-standalone/dist /app/front-standalone/dist +COPY --from=backend-builder /app/Open-OAuth2Playground/oauth2playground . +COPY --from=backend-builder /app/Open-OAuth2Playground/cfg-docker.json cfg.json + +# 复制启动脚本 +COPY start-services.sh ./start-services.sh + +# 修改文件权限 +RUN chmod +x ./oauth2playground +RUN chmod +x ./start-services.sh EXPOSE 80 -CMD ["./OAuth2Playground"] \ No newline at end of file +ENTRYPOINT ["./start-services.sh"] \ No newline at end of file diff --git a/README.MD b/README.MD deleted file mode 100644 index aa2eb85..0000000 --- a/README.MD +++ /dev/null @@ -1,288 +0,0 @@ -# Open-OAuth2Playground -Open-OAuth2Playground 是一个仿 Google [OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) 的开源版 OAuth2.0 Playground - -支持本地开箱即用,适合 OAuth2.0 的学习者测试学习 OAuth2.0 协议。 - -当运用于服务端部署时,也非常适合与 OAuth2 的接口文档配合同步发布,方便第三方调用者快速的开发调试。 - -[English](./README_en.md) | [中文](./README.md) - -![](./demo.png) - -- [Open-OAuth2Playground](#open-oauth2playground) - - [安装运行](#安装运行) - - [二进制直接运行](#二进制直接运行) - - [Linux](#linux) - - [Windows](#windows) - - [systemctl 托管](#systemctl-托管) - - [编译打包](#编译打包) - - [后端编译](#后端编译) - - [前端编译](#前端编译) - - [统一打包](#统一打包) - - [docker运行](#docker运行) - - [配置](#配置) - - [后端配置](#后端配置) - - [后端配置说明](#后端配置说明) - - [前端配置](#前端配置) - - [前端配置说明](#前端配置说明) - - [前端部署](#前端部署) - - [定制化前端菜单](#定制化前端菜单) - - [API](#api) - - [鸣谢](#鸣谢) - - -## 安装运行 - -### 二进制直接运行 -#### Linux -在 [release](https://github.com/ECNU/Open-OAuth2Playground/releases) 中下载最新的 [release] 包,解压后直接运行即可。 - -``` -mkdir Open-OAuth2Playground -cd Open-OAuth2Playground/ -wget https://github.com/ECNU/Open-OAuth2Playground/releases/download/v0.2.0/Open-OAuth2Playground-linux-0.2.0.tar.gz -tar -zxvf Open-OAuth2Playground-linux-0.2.0.tar.gz -./control start -``` -访问你服务器的 80 端口即可使用。 - -#### Windows -如果只需要在 Windows 上运行测试,可以直接下载 [release] 中的 `Open-OAuth2Playground-windows-0.2.0.zip`,解压后运行 `Open-OAuth2Playground.exe` 即可。 - -### systemctl 托管 -假定部署在 `/opt/Open-OAuth2Playground` 目录下,如果部署在其他目录修改 `playground.service` 中的 `WorkingDirectory` 和 `ExecStart` 两个字段即可。 -``` -cp playground.service /etc/systemd/system/ -systemctl daemon-reload -systemctl enable playground -systemctl start playground -``` - -### 编译打包 -获取项目源码 -``` -git clone https://github.com/ECNU/Open-OAuth2Playground.git -``` -#### 后端编译 -``` -cd Open-OAuth2Playground/ -go mod tidy -go build -``` -#### 前端编译 -``` -cd front-standalone/ -pnpm install -pnpm build -``` -#### 统一打包 -``` -cd .. -chmod +x control -./control pack -``` - -### docker运行 - -(内置用于测试的oauth2 server服务) - -#### 1.给`cas_init_script.sh`文件添加执行权限 - -执行如下命令 -```shell -chmod +x cas_init_script.sh -``` - -#### 2. 修改`docker-compose.yml`文件 - -##### 2.1 设置环境变量 - -修改`cas-demo`容器的`environment`字段 - -```yaml -environment: - - CAS_SERVER_NAME= - - SERVER_PORT= -``` - -如未设置,默认如下 - -```yaml -environment: - - CAS_SERVER_NAME=http://localhost:8444 - - SERVER_PORT=8444 -``` - -##### 2.2 修改端口映射 - -修改容器的`ports`字段 - -如第1步中`SERVER_PORT`非默认值8444,则需将`cas-demo`容器的端口修改为您设置的`SERVER_PORT`的值,注意容器和宿主机端口必须相同 - -```yml -# open-oauth2playground容器端口,可自行修改 -ports: - - "8080:80" -# cas-demo容器端口,两者需一致 -ports: - - "your_port:your_port" -``` - -#### 3. 修改`cfg.json`配置 - -##### 3.1 修改`endpoints`字段 - -将`cfg.json`文件中的`endpoints`字段中`cas server`的域名设置为第1步的`CAS_SERVER_NAME`,如第1步中未设置,则设置为`http://localhost:8444` - -```json -"endpoints": { - "authorization": "http://localhost:8444/cas/oauth2.0/authorize", - "token": "http://localhost:8444/cas/oauth2.0/accessToken", - "userinfo": "http://localhost:8444/cas/oauth2.0/profile" - } -``` -##### 3.2 修改`trust_domain`字段 -若`CAS_SERVER_NAME`是`http://localhost:8444`,则在`cfg.json`文件中的`trust_domain`字段中添加`localhost:8444`,反之添加您设置的`CAS_SERVER_NAME`的值 - -```json - "trust_domain": [ - "localhost:8444", - ] -``` - -#### 4. 启动容器 - -在`docker-compose.yml`所在目录下执行如下命令 - -```shell -docker-compose up -``` - -在`cas-domo`容器日志中看到`ready`字样,即启动成功,访问`http://localhost:8080`即可。 - - -#### 5. 注意 - -- **cas测试用户为**: -```txt -user:cas -password:123456 -``` -可编辑`cas_init_script.sh`脚本添加新用户或修改用户名、密码 -```shell -INSERT INTO user (username, password, name) VALUES ('cas', '123456', '测试用户'); -``` - -或启动后进入`cas-demo`容器/export/data/目录下,连接sqlite数据库cas.db后修改 -```shell -# 进入cas-demo容器 -docker exec -it container_id /bin/bash - -cd /export/data -# 连接数据库 -sqlite3 cas.db -``` - -[//]: # (todo:这部分要修改) -- **cas的service** - - authorization_code | client_credentials | device_flow模式: - ```txt - client_id:open-oauth2playground - password:open-oauth2playground - ``` - - pkce模式: - ```txt - client_id:open-oauth2playground-pkce - ``` -可在Open-OAuth2Playground/apereo-cas/etc/services目录下自行添加新的service - - -### 配置 -#### 后端配置 -参考 `cfg.json.example`, 创建 `cfg.jon` 配置文件,修改配置即可 -```json -{ - "logger": { - "dir": "logs/", - "level": "DEBUG", - "keepHours": 24 - }, - "endpoints": { - "authorization": "http://cas.example.org/cas/oauth2.0/authorize", - "token": "http://cas.example.org/cas/oauth2.0/accessToken", - "userinfo": "http://cas.example.org/cas/oauth2.0/profile" - }, - "iplimit": { - "enable": false, - "trust_ip": ["127.0.0.1","::1"] - }, - "http": { - "route_base":"/", - "trust_proxy": ["127.0.0.1", "::1"], - "cors": ["http://127.0.0.1:8080","http://localhost:8080"], - "listen": "0.0.0.0:80" - }, - "trust_domain": ["cas.example.org", "localhost"], - "default_scope": "Basic", - "timeout": 10 -} -``` -##### 后端配置说明 -| 配置项 | 类型 | 说明 | -| --- | --- | --- | -| logger.dir | string | 日志文件夹 | -| logger.level | string | 日志等级 | -| logger.keepHours | int | 日志保留时间 | -| endpoints.authorization | string | OAuth2.0 授权地址 | -| endpoints.token | string | OAuth2.0 获取 token 地址 | -| endpoints.userinfo | string | OAuth2.0 获取用户信息地址 | -| iplimit.enable | bool | 是否开启 IP 限制 | -| iplimit.trust_ip | []string | 可信任的 IP 列表 | -| http.route_base | string | 路由前缀,注意要和前端匹配 | -| http.trust_proxy | []string | 可信任的代理 IP 列表 | -| http.cors | []string | 允许前端跨域的域名列表 | -| http.listen | string | 监听地址 | -| trust_domain | []string | 后端转发API调用时,信任的域名列表 | -| default_scope | string | 默认的 scope | -| timeout | int | 超时时间 | - - -#### 前端配置 -修改 `.env.production` -```ini -# Router path -VUE_APP_ROUTER_BASE=/ -# Api Config -VUE_APP_API_PROTO=http -VUE_APP_API_HOST=localhost -VUE_APP_API_PORT= -VUE_APP_API_VERSION=v1 -``` -##### 前端配置说明 -| 配置项 | 类型| 说明 | -| --- | --- | --- | -| VUE_APP_ROUTER_BASE | string | 路由前缀,注意要和后端匹配 | -| VUE_APP_API_PROTO | string | 前端独立部署时需要,后端服务器的 proto | -| VUE_APP_API_HOST | string | 前端独立部署时需要,后端的域名 | -| VUE_APP_API_PORT | string | 前端独立部署时需要,后端的端口。如果是默认端口可忽略(例如https的443或者http的80) | -| VUE_APP_API_VERSION | string | API 版本,目前固定为 v1 | - -##### 前端部署 -项目的前端部分可以独立部署单独发布,也可以由后端来发布。 - -默认由后端发布,此时前端的 `VUE_APP_API_HOST`,`VUE_APP_API_PROTO`, `VUE_APP_API_PORT` 等配置项可以忽略。此时编译打包后的前端代码应该部署相对后端二进制文件的 front-standalone/dist 目录下。 - -如果前端独立部署,则需要在编译时,配置好 `VUE_APP_API_HOST`,`VUE_APP_API_PROTO`, `VUE_APP_API_PORT` 等配置项,并确保前端的域名在后端的跨域列表内。 - -##### 定制化前端菜单 - -项目的菜单部分,对应 `front-standalone/src/views/Layourt.vue` 文件,可以根据需要修改 `el-menu-item` 的内容,然后编译打包即可。 - -### API -todo - - -### 鸣谢 -本项目受 Google 的 [OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) 启发 - -感谢 Google 提供的优秀的工具。 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb6bd75 --- /dev/null +++ b/README.md @@ -0,0 +1,395 @@ +# Open-OAuth2Playground + +[English](./README_en.md) | [中文](./README.md) + +**[ 项目简介 ]** + +Open-OAuth2Playground 是一个仿 Google [OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) 的开源版 OAuth2.0 Playground 。 + +本项目支持本地开箱即用,适合 OAuth2.0 的学习者测试学习 OAuth2.0 协议。 + +当运用于服务端部署时,也非常适合与 OAuth2 的接口文档配合同步发布,方便第三方调用者快速的开发调试。 + +**注:** 本项目依赖于 [oauth-server-lite](https://github.com/shanghai-edu/oauth-server-lite/) 服务(或自行准备 / 配置用于鉴权的服务后端并修改 `cfg.json`),使用前需要先启动 oauth-server-lite 。如希望将本项目作为测试学习使用,建议使用 [方式四、docker 运行](#方式四docker-运行) 以快速拉起一套完整 Oauth2 鉴权、测试的前后端服务。 + +![Open-OAuth2Playground](imgs/demo.png) + +**[ 目录 ]** + +- [Open-OAuth2Playground](#open-oauth2playground) + - [安装运行](#安装运行) + - [方式一、docker 一键部署运行](#方式一docker-一键部署运行) + - [方式二、源码编译运行](#方式二源码编译运行) + - [1. 获取项目源码](#1-获取项目源码) + - [2. 修改配置文件](#2-修改配置文件) + - [2. 修改配置文件](#2-修改配置文件) + - [3. 前端编译](#3-前端编译) + - [4. 后端编译](#4-后端编译) + - [5. 运行](#5-运行) + - [统一打包](#统一打包) + - [方式三:二进制包-解压后直接运行](#方式三二进制包-解压后直接运行) + - [Linux](#linux) + - [Windows](#windows) + - [方式四:二进制包-systemctl 托管运行](#方式四二进制包---systemctl-托管运行) + - [配置](#配置) + - [一、后端配置](#一后端配置) + - [后端配置说明](#后端配置说明) + - [二、前端配置](#二前端配置) + - [前端配置说明](#前端配置说明) + - [三、前端项目单独部署](#三前端项目单独部署) + - [定制化前端菜单](#定制化前端菜单) + - [使用](#使用) + - [鸣谢](#鸣谢) + +--- + +## 安装运行 + +本项目提供 docker 一键部署、手动源码编译运行、二进制文件一键运行和二进制文件托管运行 4 种方式。 + +docker 运行方式 #TODO + +源码编译、二进制文件运行均依赖于 `Open-OAuth2Playground` 二进制文件和 `cfg` 配置文件。默认读取二进制文件平级目录的 `cfg.json` 文件作为配置文件,支持通过 `-c /path/to/cfg` 运行时传参的方式指定特定的 `cfg` 配置文件(systemctl 托管运行时需要自行修改 service 文件)。 + +### 方式一、docker 一键部署运行 + +(内置用于测试的 [oauth-server-lite](https://github.com/shanghai-edu/oauth-server-lite/) 服务) + +项目提供 `docker-compose.yaml` 文件,可直接一键拉起。 + +```shell +docker-compose -p oauth-server-lite up -d +``` + +**注意事项** + +- 此方式启动时,由于容器内无法直接通过 `localhost` 访问其它服务,因此需要通过访问 service name 的方式 ( `redis:6379` ) 连接 redis 。其它配置见文件。 +- `cas.db` 默认写入用户信息: + - `username: cas`,可通过配置 `${CAS_USERNAME}` 修改 + - `password: 123456`,可通过配置 `${CAS_PASSWORD}` 修改 +- `sqlite.db` 默认写入 oauth client 信息: + - `client_id: oauth`,可通过配置 `${OAUTH_CLIENT_ID}` 修改 + - `client_secret: 123456`,可通过配置 `${OAUTH_CLIENT_SECRET}` 修改 + - `domains: open-oauth2playground`,可通过配置 `${PLAYGROUND_HOST}` 修改 + - `grant_types: authorization_code,client_credentials,device_flow`, + +[//]: # (todo:这部分要修改) +- **cas的service** + - authorization_code | client_credentials | device_flow模式: + ```txt + client_id:open-oauth2playground + password:open-oauth2playground + ``` + - pkce模式: + ```txt + client_id:open-oauth2playground-pkce + ``` +可在Open-OAuth2Playground/apereo-cas/etc/services目录下自行添加新的service + +### 方式二、源码编译运行 + +此方式面向开发者 / 高级用户等有二次开发 / 定制化需求的人员。 + +该方式需要首先完成配置文件 `cfg.json` 的修改,然后依次进行 [[3 前端编译]](#3-前端编译) 和 [[4 后端编译]](#4-后端编译)。 + +#### 前期准备: + +- go >= 1.20.0 +- pnpm (npm && node ^12.0.0 || >= 14.0.0) + +#### 1. 获取项目源码 + +```shell +git clone https://github.com/ECNU/Open-OAuth2Playground.git +``` + +#### 2. 修改配置文件 + +参考 `cfg.json.example` 修改配置文件。 + +```shell +cd Open-OAuth2Playground +cp cfg.json.example cfg.json +# vim cfg.json ## 修改配置文件 +``` + +#### 3. 前端编译 + +```shell +cd front-standalone/ +# 确保在 Open-OAuth2Playground/front-standalone 目录下 +pnpm install +pnpm build +``` + +编译成功结果: + +```shell +... + + Build at: 2024-10-31T03:41:50.137Z - Hash: fa1d180a37fe6b83 - Time: 32612ms + + DONE Build complete. The dist directory is ready to be deployed. + INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html + ``` + +此时 `front-standalone` 下会编译出 `dist` 目录。 + +#### 4. 后端编译 + +```shell +cd .. +# 确保在 Open-OAuth2Playground 根目录下 +go mod tidy +go build +``` + +编译成功后,根目录下会编译出 `Open-OAuth2Playground` 二进制文件。 + +#### 5. 运行 + +```shell +./Open-OAuth2Playground +``` + +输出: + +```shell +[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. + - using env: export GIN_MODE=release + - using code: gin.SetMode(gin.ReleaseMode) + +[GIN-debug] GET /css/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) +[GIN-debug] HEAD /css/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) +[GIN-debug] GET /js/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) +[GIN-debug] HEAD /js/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) +[GIN-debug] GET / --> github.com/ECNU/Open-OAuth2Playground/controller.Routes.(*RouterGroup).StaticFile.func1 (4 handlers) +[GIN-debug] HEAD / --> github.com/ECNU/Open-OAuth2Playground/controller.Routes.(*RouterGroup).StaticFile.func1 (4 handlers) +[GIN-debug] GET /favicon.ico --> github.com/ECNU/Open-OAuth2Playground/controller.Routes.(*RouterGroup).StaticFile.func2 (4 handlers) +[GIN-debug] HEAD /favicon.ico --> github.com/ECNU/Open-OAuth2Playground/controller.Routes.(*RouterGroup).StaticFile.func2 (4 handlers) +[GIN-debug] GET /v1/config --> github.com/ECNU/Open-OAuth2Playground/controller.getConfig (4 handlers) +[GIN-debug] POST /v1/oauth2/pkce --> github.com/ECNU/Open-OAuth2Playground/controller.pkce (6 handlers) +[GIN-debug] POST /v1/oauth2/user_code --> github.com/ECNU/Open-OAuth2Playground/controller.getUserCode (6 handlers) +[GIN-debug] POST /v1/oauth2/device_flow --> github.com/ECNU/Open-OAuth2Playground/controller.deviceFlow (6 handlers) +[GIN-debug] POST /v1/oauth2/client_credentials --> github.com/ECNU/Open-OAuth2Playground/controller.clientCredentials (6 handlers) +[GIN-debug] POST /v1/oauth2/password --> github.com/ECNU/Open-OAuth2Playground/controller.passwordMode (6 handlers) +[GIN-debug] POST /v1/oauth2/authorization_code --> github.com/ECNU/Open-OAuth2Playground/controller.exchangeTokenByCode (6 handlers) +[GIN-debug] POST /v1/oauth2/refresh_token --> github.com/ECNU/Open-OAuth2Playground/controller.refreshToken (6 handlers) +[GIN-debug] POST /v1/api --> github.com/ECNU/Open-OAuth2Playground/controller.api (6 handlers) +``` + +说明服务已经正常启动。访问 [http://127.0.0.1:80](http://127.0.0.1:80) (默认)或 `cfg.json` 配置的 `.http.listen` 即可访问 Open-OAuth2Playground 。 + +#### 统一打包 + +将编译后结果统一打包为 `Open-OAuth2Playground-${release}.tar.gz`: + +```shell +cd .. +chmod +x control +./control pack +``` + +如需要增/改打包内容,请修改 control 文件。 + +### 方式三:二进制包-解压后直接运行 + +本项目提供已编译的项目压缩包,可直接下载解压运行。 + +#### Linux + +在 [release](https://github.com/ECNU/Open-OAuth2Playground/releases) 中下载最新的 [release] 包,解压后直接运行即可。 + +``` +mkdir Open-OAuth2Playground +cd Open-OAuth2Playground/ +wget https://github.com/ECNU/Open-OAuth2Playground/releases/download/v0.2.0/Open-OAuth2Playground-linux-0.2.0.tar.gz +tar -zxvf Open-OAuth2Playground-linux-0.2.0.tar.gz +./control start +# ./control stop +``` +访问你服务器的 80 端口即可使用( 默认本地访问:[http://127.0.0.1:80](http://127.0.0.1:80) )。 + +#### Windows + +如果只需要在 Windows 上运行测试,可以直接下载 [release](https://github.com/ECNU/Open-OAuth2Playground/releases) 中的 `Open-OAuth2Playground-windows-0.2.0.zip`,解压后运行 `Open-OAuth2Playground.exe` 即可。 + +### 方式四:二进制包 - systemctl 托管运行 + +[[方式三、二进制包-解压后直接运行]](#方式三二进制包-解压后直接运行) 也可基于 systemctl 实现自动托管运行。 + +``` +# 1. 在 /opt/Open-OAuth2Playground 下,下载解压 release 包 +cd /opt +mkdir Open-OAuth2Playground +cd Open-OAuth2Playground/ +wget https://github.com/ECNU/Open-OAuth2Playground/releases/download/v0.2.0/Open-OAuth2Playground-linux-0.2.0.tar.gz +tar -zxvf Open-OAuth2Playground-linux-0.2.0.tar.gz + +# 2. 创建 service 文件 +# 请根据具体需要调整文件内容 + +# 方式一:直接写入 +sudo tee /etc/systemd/system/playground.service > /dev/null << 'EOF' +[Unit] +Description=playground +After=network-online.target +Wants=network-online.target + +[Service] +# modify when deploy in prod env +User=root +Group=root + +Type=simple +ExecStart=/opt/Open-OAuth2Playground/Open-OAuth2Playground +WorkingDirectory=/opt/Open-OAuth2Playground + +Restart=always +RestartSec=1 +StartLimitInterval=0 + +[Install] +WantedBy=multi-user.target +EOF + +# 方式二:拷贝压缩包自带的 playground.service 到 system 目录 +# cp playground.service /etc/systemd/system/playground.service + +# 3. 启动 playground.service +systemctl daemon-reload +systemctl enable playground +systemctl start playground +``` + +此时文件树结构如下(`Open-OAuth2Playground` 二进制文件和 `cfg.json` 配置文件存在即可)。如果部署在其他目录,修改 `playground.service` 中的 `WorkingDirectory` 和 `ExecStart` 两个字段即可。 + +```shell +[root@iZm05jcnfytljnZ Open-OAuth2Playground]# tree /opt +/opt +└── Open-OAuth2Playground + ├── cfg.json + ├── control + ├── front-standalone + │ ├── dist + │ │ ├── css + │ │ │ ├── ... + │ │ └── js + │ │ └── ... + │ └── ... + ├── gitversion + ├── logs + │ ├── DEBUG.log + │ ├── INFO.log + │ └── *.log + ├── Open-OAuth2Playground + └── Open-OAuth2Playground-linux-0.2.0.tar.gz +``` + +## 配置 + +### 一、后端配置 + +参考 `cfg.json.example`, 创建 `cfg.jon` 配置文件,修改配置即可。 + +```json +{ + "logger": { + "dir": "logs/", + "level": "DEBUG", + "keepHours": 24 + }, + "endpoints": { + "authorization": "http://oauth.example.org/oauth2/device/authorize", + "token": "http://oauth.example.org/oauth2/token", + "userinfo": "http://oauth.example.org/oauth2/userinfo" + }, + "iplimit": { + "enable": false, + "trust_ip": ["127.0.0.1","::1"] + }, + "http": { + "route_base":"/", + "trust_proxy": ["127.0.0.1", "::1"], + "cors": ["http://127.0.0.1:8080","http://localhost:8080"], + "listen": "0.0.0.0:80" + }, + "trust_domain": ["oauth.example.org", "localhost"], + "default_scope": "Basic", + "timeout": 10 +} +``` + +#### 后端配置说明 + +| 配置项 | 类型 | 说明 | +|-------------------------|----------|----------------------| +| logger.dir | string | 日志文件夹 | +| logger.level | string | 日志等级 | +| logger.keepHours | int | 日志保留时间 | +| endpoints.authorization | string | OAuth2.0 授权地址 | +| endpoints.token | string | OAuth2.0 获取 token 地址 | +| endpoints.userinfo | string | OAuth2.0 获取用户信息地址 | +| iplimit.enable | bool | 是否开启 IP 限制 | +| iplimit.trust_ip | []string | 可信任的 IP 列表 | +| http.route_base | string | 路由前缀,注意要和前端匹配 | +| http.trust_proxy | []string | 可信任的代理 IP 列表 | +| http.cors | []string | 允许前端跨域的域名列表 | +| http.listen | string | 监听地址 | +| trust_domain | []string | 后端转发API调用时,信任的域名列表 | +| default_scope | string | 默认的 scope | +| timeout | int | 超时时间 | + +### 二、前端配置 + +修改 `.env.production`: + +```ini +# Router path +VUE_APP_ROUTER_BASE=/ +# Api Config +VUE_APP_API_PROTO=http +VUE_APP_API_HOST=localhost +VUE_APP_API_PORT= +VUE_APP_API_VERSION=v1 +``` + +#### 前端配置说明 + +| 配置项 | 类型 | 说明 | +|---------------------|--------|--------------------------------------------------| +| VUE_APP_ROUTER_BASE | string | 路由前缀,注意要和后端匹配 | +| VUE_APP_API_PROTO | string | 前端独立部署时需要,后端服务器的 proto | +| VUE_APP_API_HOST | string | 前端独立部署时需要,后端的域名 | +| VUE_APP_API_PORT | string | 前端独立部署时需要,后端的端口。如果是默认端口可忽略(例如https的443或者http的80) | +| VUE_APP_API_VERSION | string | API 版本,目前固定为 v1 | + +### 三、前端项目单独部署 + +项目的前端部分可以独立部署单独发布,也可以由后端来发布。 + +默认由后端发布,此时前端的 `VUE_APP_API_HOST`,`VUE_APP_API_PROTO`, `VUE_APP_API_PORT` 等配置项可以忽略。此时编译打包后的前端代码应该部署相对后端二进制文件的 front-standalone/dist 目录下。 + +如果前端独立部署,则需要在编译时,配置好 `VUE_APP_API_HOST`,`VUE_APP_API_PROTO`, `VUE_APP_API_PORT` 等配置项,并确保前端的域名在后端的跨域列表内。 + +#### 定制化前端菜单 + +项目的菜单部分,对应 `front-standalone/src/views/Layourt.vue` 文件,可以根据需要修改 `el-menu-item` 的内容,然后编译打包即可。 + +## 使用 + +### 一、Authorization Code 模式 + +### 二、Resource Owner Password Credentials 模式 + +### 三、Client Credentials 模式 + +### 四、Device Flow 模式 + +### 五、PKCE 模式 + +## 鸣谢 + +本项目受 Google 的 [OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) 启发 + +感谢 Google 提供的优秀的工具。 \ No newline at end of file diff --git a/cas_init_script.sh b/cas_init_script.sh deleted file mode 100644 index 8a23a28..0000000 --- a/cas_init_script.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# cas_init_script.sh - -mkdir -p /export/data/ -chmod 777 /export/data/ -sqlite3 /export/data/cas.db <> "$CAS_PROPERTIES_FILE" -fi - -# 检查并替换或添加 cas.server.name -if grep -q "cas.server.name" "$CAS_PROPERTIES_FILE"; then - sed -i "s#cas.server.name=.*#cas.server.name=${CAS_SERVER_NAME}#" "$CAS_PROPERTIES_FILE" -else - echo "cas.server.name=${CAS_SERVER_NAME}" >> "$CAS_PROPERTIES_FILE" -fi - -echo "read configuration successfully!" \ No newline at end of file diff --git a/cfg-docker.json b/cfg-docker.json index 70b3be1..8732ff6 100644 --- a/cfg-docker.json +++ b/cfg-docker.json @@ -5,10 +5,10 @@ "keepHours": 24 }, "endpoints": { - "authorization": "http://localhost/oauth2/authorize", - "token": "http://oauth-server-lite/oauth2/token", - "userinfo": "http://oauth-server-lite/oauth2/userinfo", - "device_authorization": "http://oauth-server-lite/oauth2/device/authorize" + "authorization": "http://localhost:8081/oauth2/authorize", + "device_authorization": "http://localhost:8081/oauth2/device/authorize", + "token": "http://localhost:8081/oauth2/token", + "userinfo": "http://localhost:8081/oauth2/userinfo" }, "iplimit": { "enable": false, @@ -17,10 +17,10 @@ "http": { "route_base":"/", "trust_proxy": ["127.0.0.1", "::1"], - "cors": ["http://127.0.0.1","http://localhost"], - "listen": "0.0.0.0:8080" + "cors": ["localhost", "127.0.0.1"], + "listen": "0.0.0.0:80" }, - "trust_domain": ["api.ecnu.edu.cn", "localhost", "oauth-server-lite"], + "trust_domain": ["localhost", "localhost:8081"], "default_scope": "Basic", "timeout": 10 } \ No newline at end of file diff --git a/cfg.json.example b/cfg.json.example index ecb5e11..18e9deb 100644 --- a/cfg.json.example +++ b/cfg.json.example @@ -5,9 +5,10 @@ "keepHours": 24 }, "endpoints": { - "authorization": "http://cas.example.org/cas/oauth2.0/authorize", - "token": "http://cas.example.org/cas/oauth2.0/accessToken", - "userinfo": "http://cas.example.org/cas/oauth2.0/profile" + "authorization": "http://oauth.example.org/oauth2/authorize", + "device_authorization": "http://oauth.example.org/oauth2/device/authorize", + "token": "http://oauth.example.org/oauth2/token", + "userinfo": "http://oauth.example.org/oauth2/userinfo" }, "iplimit": { "enable": false, @@ -16,10 +17,10 @@ "http": { "route_base":"/", "trust_proxy": ["127.0.0.1", "::1"], - "cors": ["http://127.0.0.1:8080","http://localhost:8080"], + "cors": ["localhost", "127.0.0.1"], "listen": "0.0.0.0:80" }, - "trust_domain": ["cas.example.org", "localhost"], + "trust_domain": ["localhost", "oauth.example.org"], "default_scope": "Basic", "timeout": 10 } \ No newline at end of file diff --git a/control b/control index ad14415..66eeb5c 100644 --- a/control +++ b/control @@ -77,7 +77,7 @@ function pack() { build git log -1 --pretty=%h > gitversion version=`./$app -v` - file_list="front-standalone control cfg.json cfg.json.example $app" + file_list="front-standalone control cfg.json cfg.json.example playground.service $app" echo "...tar $app-$version.tar.gz <= $file_list" tar zcf $app-$version.tar.gz gitversion $file_list } diff --git a/docker-build.sh b/docker-build.sh new file mode 100644 index 0000000..0bed369 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# 构建方式: 本地构建 or 多平台构建打包上传镜像 +BUILD_MODE="local" # local / remote + +# DockerHub 用户名、镜像名称和版本号 +USERNAME="ecnunic" +IMAGE_NAME="open-oauth2playground" +VERSION="v0.2.0" + +# 支持的架构列表 +PLATFORMS="linux/amd64,linux/arm64" + +# 完整的镜像标签 +FULL_TAG="${USERNAME}/${IMAGE_NAME}:${VERSION}" + +echo "Building ${FULL_TAG} for platforms ${PLATFORMS}..." + +if [ "${BUILD_MODE}" == "remote" ]; then + # 推送到远程镜像仓库 + docker buildx build \ + --platform "${PLATFORMS}" \ + -t "${FULL_TAG}" \ + --push . +elif [ "${BUILD_MODE}" == "local" ]; then + # 本地构建 + docker build --no-cache --load -t "${FULL_TAG}" . +else + # Unknown $BUILD_MODE + echo "BUILD_MODE must be \`local\` or \`remote\`, but got \`${BUILD_MODE}\`" +fi \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..efe3584 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,70 @@ +# 启动命令: docker-compose -p open-oauth2playground up -d +# -p [service name] 其中 server_name 可以替换为任意的服务名称 + +# container model: 容器模式。由 open-oauth2playground 容器网络统一暴露端口 +# container 模式下的容器无法暴露自身端口 + +services: + + open-oauth2playground: + image: ecnunic/open-oauth2playground:v0.2.0 + container_name: open-oauth2playground + environment: + - PLAYGROUND_PORT=80 # oauth2playground 服务端口号 + - PLAYGROUND_HOST=localhost # oauth2playground 服务地址/域名 (用于配置域名解析) + - CAS_SERVER_HOST=localhost # apereo-cas 服务地址/域名 (用于配置域名解析) + - OAUTH_SERVER_PORT=8081 # oauth-server-lite 服务端口号 + - OAUTH_SERVER_HOST=localhost # oauth-server-lite 服务地址/域名 (用于服务通信 && 配置域名解析) + - OAUTH_SERVER_URL=http://localhost:8081 # oauth-server-lite 服务 URL + ports: + - "80:80" # open-oauth2playground 端口 + # - "6379:6379" # redis 端口 + - "8080:8080" # apereo-cas 服务占用 1 + - "8081:8081" # oauth-server-lite 前端服务 + - "8444:8444" # apereo-cas 服务占用 2 + networks: + - open-oauth2playground + # volumes: + # - ./oauth-server-lite/oauth2playground/cfg.json:/app/cfg.json + # - ./oauth-server-lite/oauth2playground/logs:/app/logs + restart: always + + redis: + image: redis:alpine + container_name: oauth-redis + depends_on: + - open-oauth2playground + network_mode: container:open-oauth2playground + restart: always + + oauth-server-lite: + image: ecnunic/oauth-server-lite:v0.3.0 + container_name: oauth-server-lite + environment: + - OAUTH_CLIENT_ID=oauth # OAuth2 Client ID + - OAUTH_CLIENT_SECRET=123456 # OAuth2 Client Secret + - CAS_USERNAME=cas # CAS 用户名 + - CAS_PASSWORD=123456 # CAS 用户密码 + - OAUTH_SERVER_PORT=8081 # oauth-server-lite 服务端口号 + - CAS_SERVER_PORT=8444 # apereo-cas 服务端口号 + - CAS_SERVER_HOST=localhost # apereo-cas 服务地址/域名 + - CAS_SERVER_URL=http://localhost:8444 # apereo-cas 服务 URL + - OAUTH_REDIS_DSN=localhost:6379 # redis 服务地址/域名 + - OAUTH_REDIS_PASSWORD= # redis 服务连接密码 + - PLAYGROUND_HOST=localhost # oauth2playground 服务地址/域名 + depends_on: + - open-oauth2playground + - redis + network_mode: container:open-oauth2playground +# volumes: +# - ./oauth-server-lite/apereo-cas/cas.db:/app/apereo-cas/cas.db # apereo-cas 用户信息 sqlite 数据库 +# - ./oauth-server-lite/apereo-cas/config:/etc/cas/config # apereo-cas 配置信息 +# - ./oauth-server-lite/apereo-cas/services:/etc/cas/services # apereo-cas 服务配置 +# - ./oauth-server-lite/oauth-server-lite/sqlite.db:/app/oauth-server-lite/sqlite.db # oauth-server-lite 认证信息 sqlite 数据库 +# - ./oauth-server-lite/oauth-server-lite/cfg.json:/app/oauth-server-lite/cfg.json # oauth-server-lite 配置信息 +# - ./oauth-server-lite/oauth-server-lite/logs:/app/oauth-server-lite/logs # oauth-server-lite 日志 + restart: always + +networks: + open-oauth2playground: + driver: bridge \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 17cb6db..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: '3' -services: - redis: - image: redis:latest - container_name: oauth-redis - ports: - - "6379:6379" - open-oauth2playground: - image: open-oauth2playground:v2.0 - container_name: open-oauth2playground - restart: always - ports: - - "8085:8080" - volumes: - - ./cfg-docker.json:/app/Open-OAuth2Playground/cfg.json - command: ["/app/Open-OAuth2Playground/OAuth2Playground"] - oauth-server-lite: -# image: ecnunic/oauth-server-lite:v1.0 - image: lite-server-test:0716 - container_name: oauth-server-lite - depends_on: - - redis - restart: always - environment: - - CLIENT_HOST=127.0.0.1 - ports: - - "80:80" - - "8444:8444" \ No newline at end of file diff --git a/demo.png b/imgs/demo.png similarity index 100% rename from demo.png rename to imgs/demo.png diff --git a/main.go b/main.go index 5f6a5a7..2867bce 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "flag" "fmt" "log" @@ -31,7 +32,7 @@ func main() { go func() { // service connections - if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("listen: %s", err) } }() diff --git a/start-services.sh b/start-services.sh new file mode 100644 index 0000000..568f34d --- /dev/null +++ b/start-services.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +# author: dbbDylan +# date: 2024.11.09 +# note: depends on `jq` + +set -e # 监测到错误立即退出 + +# ======================== +# 变量定义 +# ======================== + +# docker 容器中各(配置)文件以及目录的路径 +PATH_ROOT=${PATH_ROOT:-"/oauth2playground"} +PLAYGROUND_PATH="${PATH_ROOT}/oauth2playground" +PLAYGROUND_CONFIG_FILE="${PATH_ROOT}/cfg.json" + +# 可对外暴露的环境变量 +PLAYGROUND_PORT=${PLAYGROUND_PORT:-"80"} # oauth2playground 服务端口号 +PLAYGROUND_HOST=${PLAYGROUND_HOST:-"localhost"} # oauth2playground 服务地址/域名 +CAS_SERVER_HOST=${CAS_SERVER_HOST:-"localhost"} # apereo-cas 服务地址/域名 +OAUTH_SERVER_PORT=${OAUTH_SERVER_PORT:-"8081"} # oauth-server-lite 服务端口号 +OAUTH_SERVER_HOST=${OAUTH_SERVER_HOST:-"localhost"} # oauth-server-lite 服务地址/域名 +OAUTH_SERVER_URL=${OAUTH_SERVER_URL:-"http://${OAUTH_SERVER_HOST}:${OAUTH_SERVER_PORT}"} # oauth-server-lite 服务 URL + +# ======================== +# 函数定义 +# ======================== + +# 配置 oauth2playground cfg.json +configure_oauth2_playground() { + echo "Configuring OAuth2 Playground..." + + # 更新 .endpoints 中的指定字段 + jq --arg url "$OAUTH_SERVER_URL" ' + .endpoints.device_authorization = "\($url)/oauth2/device/authorize" | + .endpoints.token = "\($url)/oauth2/token" | + .endpoints.userinfo = "\($url)/oauth2/userinfo" + ' "$PLAYGROUND_CONFIG_FILE" > "$PLAYGROUND_CONFIG_FILE.tmp" && mv "$PLAYGROUND_CONFIG_FILE.tmp" "$PLAYGROUND_CONFIG_FILE" + + # 更新 .http 字段 + jq --arg port "$PLAYGROUND_PORT" \ ' + .http.listen = "0.0.0.0:\($port)" + ' "$PLAYGROUND_CONFIG_FILE" > "$PLAYGROUND_CONFIG_FILE.tmp" && mv "$PLAYGROUND_CONFIG_FILE.tmp" "$PLAYGROUND_CONFIG_FILE" + + # 仅在 trust_domain 中不存在时追加新值 + jq --arg new_domain "${OAUTH_SERVER_URL}" ' + if .trust_domain | index($new_domain) == null then + .trust_domain += [$new_domain] + else + . + end + ' "$PLAYGROUND_CONFIG_FILE" > "$PLAYGROUND_CONFIG_FILE.tmp" && mv "$PLAYGROUND_CONFIG_FILE.tmp" "$PLAYGROUND_CONFIG_FILE" + + echo "OAuth2 Playground configured successfully!" +} + +configure_domain_parser() { + echo "Configuring domain parser..." + + # 检查并添加 PLAYGROUND_DOMAIN 的解析 + if [ "${PLAYGROUND_HOST}" != "localhost" ] && [ "${PLAYGROUND_HOST}" != "127.0.0.1" ]; then + if ! grep -q "${PLAYGROUND_HOST}" /etc/hosts; then + echo "127.0.0.1 ${PLAYGROUND_HOST}" >> /etc/hosts + echo "Added DNS resolution for PLAYGROUND_HOST: ${PLAYGROUND_HOST}" + else + echo "DNS resolution for PLAYGROUND_HOST already exists: ${PLAYGROUND_HOST}" + fi + fi + + # 检查并添加 OAUTH_SERVER_DOMAIN 的解析 + if [ "${OAUTH_SERVER_HOST}" != "localhost" ] && [ "${OAUTH_SERVER_HOST}" != "127.0.0.1" ]; then + if ! grep -q "${OAUTH_SERVER_HOST}" /etc/hosts; then + echo "127.0.0.1 ${OAUTH_SERVER_HOST}" >> /etc/hosts + echo "Added DNS resolution for OAUTH_SERVER_HOST: ${OAUTH_SERVER_HOST}" + else + echo "DNS resolution for OAUTH_SERVER_HOST already exists: ${OAUTH_SERVER_HOST}" + fi + fi + + echo "Domain parser configuration completed!" +} + +# 启动 OAuth2 Playground 服务 +start_oauth2_playground() { + echo "Starting OAuth2 Playground..." + + cd "${PATH_ROOT}" && ${PLAYGROUND_PATH} -c "${PLAYGROUND_CONFIG_FILE}" & +} + +# ======================== +# 主执行流程 +# ======================== +configure_oauth2_playground +configure_domain_parser +start_oauth2_playground + +# 保持脚本运行 +echo "All services started. Keeping script running..." +tail -f /dev/null \ No newline at end of file