非常好, 我们可以在现有基础上添加用户认证功能, 使用 Google 和 GitHub 的 OAuth 2 认证。以下是实现步骤:
- 首先, 安装必要的依赖:
bun add @elysiajs/cookie @elysiajs/jwt oauth4webapi-
在 Google Cloud Console 和 GitHub Developer settings 中创建 OAuth 应用, 获取客户端 ID 和密钥。
-
创建一个新的配置文件
config.ts:
// config.ts
export const config = {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
redirectUri: 'http://localhost:3000/auth/google/callback',
},
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
redirectUri: 'http://localhost:3000/auth/github/callback',
},
jwt: {
secret: process.env.JWT_SECRET || 'your-secret-key',
},
}- 创建一个认证处理模块
auth.ts:
// auth.ts
import { Elysia } from 'elysia'
import { cookie } from '@elysiajs/cookie'
import { jwt } from '@elysiajs/jwt'
import * as oauth from 'oauth4webapi'
import { config } from './config'
export const auth = (app: Elysia) =>
app
.use(cookie())
.use(
jwt({
name: 'jwt',
secret: config.jwt.secret,
})
)
.get('/auth/google', async ({ set }) => {
const client = new oauth.Client({
clientId: config.google.clientId,
clientSecret: config.google.clientSecret,
})
const authorizationUrl = await oauth.getAuthorizationUrl(client, {
scope: ['openid', 'profile', 'email'],
redirectUri: config.google.redirectUri,
})
set.redirect = authorizationUrl
})
.get('/auth/google/callback', async ({ query, jwt, setCookie, set }) => {
const client = new oauth.Client({
clientId: config.google.clientId,
clientSecret: config.google.clientSecret,
})
const tokens = await oauth.getTokens(client, {
code: query.code as string,
redirectUri: config.google.redirectUri,
})
const userinfo = await oauth.getUserInfo(client, tokens)
const token = await jwt.sign({
id: userinfo.sub,
email: userinfo.email,
name: userinfo.name,
})
setCookie('auth', token, {
httpOnly: true,
maxAge: 7 * 86400,
})
set.redirect = '/'
})
.get('/auth/github', async ({ set }) => {
const client = new oauth.Client({
clientId: config.github.clientId,
clientSecret: config.github.clientSecret,
})
const authorizationUrl = await oauth.getAuthorizationUrl(client, {
scope: ['user:email'],
redirectUri: config.github.redirectUri,
})
set.redirect = authorizationUrl
})
.get('/auth/github/callback', async ({ query, jwt, setCookie, set }) => {
const client = new oauth.Client({
clientId: config.github.clientId,
clientSecret: config.github.clientSecret,
})
const tokens = await oauth.getTokens(client, {
code: query.code as string,
redirectUri: config.github.redirectUri,
})
const userinfo = await oauth.getUserInfo(client, tokens)
const token = await jwt.sign({
id: userinfo.id,
email: userinfo.email,
name: userinfo.name,
})
SetCookie ('auth', token, {
HttpOnly: true,
maxAge: 7 * 86400,
})
set.redirect = '/'
})
.get('/auth/logout', ({ removeCookie, set }) => {
removeCookie('auth')
set.redirect = '/'
})
.derive(async ({ cookie, jwt }) => {
const authCookie = cookie.auth
if (!authCookie) return { user: null }
try {
const user = await jwt.verify(authCookie)
return { user }
} catch {
return { user: null }
}
})- 修改
src/index.ts文件, 集成认证功能:
import { Elysia } from 'elysia'
import { html } from '@elysiajs/html'
import { createClient } from '@libsql/client'
import { staticPlugin } from '@elysiajs/static'
import { auth } from './auth'
import 'unocss'
// ... (保留之前的代码)
const app = new Elysia()
.use(html())
.use(staticPlugin())
.use(auth)
.get('/', ({ html, user }) => html`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Job Board</title>
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
<script src="https://unpkg.com/unocss@0.51.8/dist/unocss.js"></script>
</head>
<body class="p-4" id="main-body">
<header class="flex justify-between items-center mb-4">
<h1 class="text-2xl font-bold">Job Board</h1>
${user
? `<div>
Welcome, ${user.name}!
<a href="/auth/logout" class="ml-2 text-blue-500">Logout</a>
</div>`
: `<div>
<a href="/auth/google" class="text-blue-500 mr-2">Login with Google</a>
<a href="/auth/github" class="text-blue-500">Login with GitHub</a>
</div>`
}
</header>
${user
? `<div class="mb-4">
<label for="template-select">Choose a template:</label>
<select id="template-select" hx-get="/apply-template" hx-target="#main-body" hx-swap="outerHTML">
<option value="sunny">Sunny Sky</option>
<option value="night">Night Sky</option>
<option value="sunset">Red Sunset</option>
<option value="rainy">Gentle Rain</option>
<option value="snowy">Winter Snow</option>
</select>
<button hx-get="/edit-template" class="ml-2 bg-blue-500 text-white p-2 rounded">Edit Template</button>
</div>
<div id="job-list" hx-get="/jobs" hx-trigger="load"></div>
<form hx-post="/jobs" hx-target="#job-list" class="mt-4">
<input type="text" name="title" placeholder="Job Title" required class="border p-2 mb-2 w-full">
<input type="text" name="company" placeholder="Company" required class="border p-2 mb-2 w-full">
<textarea name="description" placeholder="Job Description" required class="border p-2 mb-2 w-full h-32"></textarea>
<button type="submit" class="bg-blue-500 text-white p-2 rounded">Post Job</button>
</form>`
: `<p>Please login to view and post jobs.</p>`
}
</body>
</html>
`)
// ... (保留之前的路由)
.listen (3000)
console.log(`Elysia is running at ${app.server?.hostname}:${app.server?.port}`)- 更新其他路由以检查用户认证:
.get('/jobs', async ({ user }) => {
if (!user) return 'Please login to view jobs.'
const jobs = await db.execute('SELECT * FROM jobs ORDER BY created_at DESC')
// ... (返回职位列表)
})
.post('/jobs', async ({ body, user }) => {
If (! User) return 'Please login to post jobs.'
const { title, company, description } = body
// ... (创建新职位)
})
.get('/apply-template', ({ query, user }) => {
if (!user) return 'Please login to apply templates.'
// ... (应用模板)
})
.get('/edit-template', ({ html, user }) => {
if (!user) return 'Please login to edit templates.'
// ... (编辑模板)
})
.post('/save-template', ({ body, user }) => {
if (!user) return 'Please login to save templates.'
// ... (保存模板)
})- 确保在你的环境变量中设置了必要的配置:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
JWT_SECRET=your_jwt_secret
这个实现添加了以下功能:
- 使用 Google 和 GitHub 的 OAuth2认证
- 用户登录和注销功能
- 基于 JWT 的会话管理
- 根据用户认证状态显示不同的内容
- 限制某些操作只能由已登录用户执行
请注意, 这个实现仍然是基本的, 你可能需要根据你的具体需求进行进一步的改进, 例如:
- 添加用户角色和权限管理
- 实现用户个人资料页面
- 添加更多的认证提供商
- 改进错误处理和用户反馈
- 实现更安全的密钥管理策略
此外, 在生产环境中, 你应该使用 HTTPS 来保护用户数据和认证过程。