fix: replace discourse host with env & typo, update README

This commit is contained in:
Tuluobo 2024-09-26 09:27:15 +08:00
parent b8368cfc32
commit b8f7fcf180
7 changed files with 173 additions and 31 deletions

View File

@ -10,7 +10,9 @@ NEXT_PUBLIC_HOST_URL=
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
# NextAuth.js # Next Auth
AUTH_SECRET= AUTH_SECRET=
DISCOUSE_SECRET= # Discourse SSO
DISCOURSE_HOST=
DISCOURSE_SECRET=

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Tuluobo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

157
README.md
View File

@ -1,36 +1,153 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). # Discourse Connect
## Getting Started 这是一个基于 [Next.js](https://nextjs.org/) 的项目,实现了使用 Discourse SSO (Single Sign-On) 用户系统的 OAuth 认证功能。
First, run the development server: ## 项目概述
本项目提供了一个 OAuth 认证系统,允许其他应用程序使用 Discourse 论坛的用户账号进行身份验证。这样可以让用户使用他们已有的 Discourse 账号登录到您的应用程序,无需创建新的账号。
主要特性:
- 基于 Discourse SSO 的用户认证
- OAuth 2.0 协议支持
- 使用 Next.js 框架构建,提供良好的性能和开发体验
## 开始使用
首先,运行开发服务器:
```bash ```bash
npm run dev
# or
yarn dev
# or
pnpm dev pnpm dev
# or # 或
bun dev pnpm turbo
``` ```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 在浏览器中打开 [http://localhost:3000](http://localhost:3000) 查看结果。
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 您可以通过修改 `app/page.tsx` 来开始编辑页面。当您编辑文件时,页面会自动更新。
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. ## 配置
## Learn More 要使用此 OAuth 系统,您需要进行以下配置:
To learn more about Next.js, take a look at the following resources: 1. 在您的 Discourse 论坛中启用 SSO 功能。
2. 设置环境变量:
- `NEXT_PUBLIC_HOST_URL`: 应用程序的主机 URL不要在末尾添加 "/"
- `DATABASE_URL`: 数据库连接字符串
- `AUTH_SECRET`: Next Auth 的密钥
- `DISCOURSE_HOST`: 您的 Discourse 论坛 URL
- `DISCOURSE_SECRET`: 在 Discourse 中设置的 SSO secret
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. ## 部署
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! ### 使用 Docker 部署
## Deploy on Vercel 本项目支持使用 Docker 进行部署。以下是使用 Docker Compose 部署的步骤:
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 1. 确保您的系统已安装 Docker 和 Docker Compose。
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 2. 在项目根目录下,运行以下命令启动服务:
```bash
docker-compose up -d
```
这将构建并启动 Web 应用和 PostgreSQL 数据库服务。
3. 应用将在 http://localhost:3000 上运行。
4. 要停止服务,运行:
```bash
docker-compose down
```
### 使用 Vercel 部署
另一种部署 Next.js 应用程序的简单方法是使用 [Vercel 平台](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)。
查看我们的 [Next.js 部署文档](https://nextjs.org/docs/deployment) 了解更多详情。
## OAuth 2.0 接口
本项目实现了基于 OAuth 2.0 协议的认证系统。以下是主要的 OAuth 接口及其使用说明:
### 1. 授权请求
**端点:** `/oauth/authorize`
**方法:** GET
**参数:**
- `response_type`: 必须为 "code"
- `client_id`: 您的客户端 ID
- `redirect_uri`: 授权后重定向的 URI
- `scope`: (可选)请求的权限范围
**示例:**
```
/oauth/authorize?response_type=code&client_id=your_client_id&redirect_uri=https://your-app.com/callback
```
### 2. 获取访问令牌
**端点:** `/api/oauth/access_token`
**方法:** POST
**参数:**
- `code`: 从授权请求中获得的授权码
- `redirect_uri`: 必须与授权请求中的 redirect_uri 相同
**响应:**
```json
{
"access_token": "at_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"expires_in": 604800,
"token_type": "bearer"
}
```
### 3. 获取用户信息
**端点:** `/api/oauth/user`
**方法:** GET
**请求头:**
- `Authorization: Bearer {access_token}`
**响应:**
```json
{
"id": "user_id",
"email": "user@example.com",
"username": "username",
"admin": false,
"avatar_url": "https://example.com/avatar.jpg",
"name": "User Name"
}
```
### 使用流程
1. 将用户重定向到授权页面(`/oauth/authorize`)。
2. 用户授权后,您的应用将收到一个授权码。
3. 使用授权码请求访问令牌(`/api/oauth/access_token`)。
4. 使用访问令牌获取用户信息(`/api/oauth/user`)。
注意:确保在生产环境中使用 HTTPS 来保护所有的 OAuth 请求和响应。
## 贡献
欢迎贡献代码、报告问题或提出改进建议。
## 许可证
本项目采用 MIT 许可证。详情请见 [LICENSE](LICENSE) 文件。

View File

@ -6,7 +6,7 @@ services:
- "3000:3000" - "3000:3000"
restart: always restart: always
environment: environment:
DATABASE_URL: postgresql://next:next@db:5432/next DATABASE_URL: postgresql://discourse_connect:discourse_connect@db:5432/discourse_connect
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@ -19,9 +19,9 @@ services:
db: db:
image: postgres:15-alpine image: postgres:15-alpine
environment: environment:
POSTGRES_DB: next POSTGRES_DB: discourse_connect
POSTGRES_USER: next POSTGRES_USER: discourse_connect
POSTGRES_PASSWORD: next POSTGRES_PASSWORD: discourse_connect
volumes: volumes:
- next-db-data:/var/lib/postgresql/data - next-db-data:/var/lib/postgresql/data
restart: always restart: always

View File

@ -8,7 +8,8 @@ import WordArray from "crypto-js/lib-typedarrays";
import { AUTH_NONCE } from "@/lib/constants"; import { AUTH_NONCE } from "@/lib/constants";
const appHost = process.env.NEXT_PUBLIC_HOST_URL; const appHost = process.env.NEXT_PUBLIC_HOST_URL;
const oauthSecret = process.env.DISCOUSE_SECRET || ""; const discourseHost = process.env.DISCOURSE_HOST;
const oauthSecret = process.env.DISCOURSE_SECRET || "";
export async function getDiscourseSSOUrl(searchParams: string) { export async function getDiscourseSSOUrl(searchParams: string) {
console.log(`searchParams: ${searchParams}`); console.log(`searchParams: ${searchParams}`);
@ -19,5 +20,5 @@ export async function getDiscourseSSOUrl(searchParams: string) {
const sig = hmacSHA256(sso, oauthSecret).toString(Hex); const sig = hmacSHA256(sso, oauthSecret).toString(Hex);
cookies().set(AUTH_NONCE, nonce, { maxAge: 60 * 10 }); cookies().set(AUTH_NONCE, nonce, { maxAge: 60 * 10 });
return `https://shuzimumin.com/session/sso_provider?sso=${sso}&sig=${sig}`; return `${discourseHost}/session/sso_provider?sso=${sso}&sig=${sig}`;
} }

View File

@ -6,7 +6,8 @@ import WordArray from "crypto-js/lib-typedarrays";
import { AUTH_NONCE } from "@/lib/constants"; import { AUTH_NONCE } from "@/lib/constants";
const hostUrl = process.env.NEXT_PUBLIC_HOST_URL as string; const hostUrl = process.env.NEXT_PUBLIC_HOST_URL as string;
const clientSecret = process.env.DISCOUSE_SECRET as string; const discourseHost = process.env.DISCOURSE_HOST as string;
const clientSecret = process.env.DISCOURSE_SECRET as string;
export async function POST(_req: Request) { export async function POST(_req: Request) {
const nonce = WordArray.random(16).toString(); const nonce = WordArray.random(16).toString();
@ -16,6 +17,6 @@ export async function POST(_req: Request) {
cookies().set(AUTH_NONCE, nonce, { maxAge: 60 * 10 }); cookies().set(AUTH_NONCE, nonce, { maxAge: 60 * 10 });
return Response.json({ return Response.json({
sso_url: `https://shuzimumin.com/session/sso_provider?sso=${sso}&sig=${sig}`, sso_url: `${discourseHost}/session/sso_provider?sso=${sso}&sig=${sig}`,
}); });
} }

View File

@ -8,7 +8,7 @@ import hmacSHA256 from "crypto-js/hmac-sha256";
import { AUTH_NONCE } from "@/lib/constants"; import { AUTH_NONCE } from "@/lib/constants";
import { createUser, getUserById, updateUser } from "@/lib/dto/user"; import { createUser, getUserById, updateUser } from "@/lib/dto/user";
const DISCOUSE_SECRET = process.env.DISCOUSE_SECRET as string; const DISCOUSE_SECRET = process.env.DISCOURSE_SECRET as string;
export async function discourseCallbackVerify(sso: string, sig: string) { export async function discourseCallbackVerify(sso: string, sig: string) {
// 校验数据正确性 // 校验数据正确性