only use supabase token

This commit is contained in:
2025-03-10 13:38:39 +08:00
parent 936af0c4ec
commit 4b5910be83
3 changed files with 86 additions and 80 deletions

View File

@@ -1,17 +1,7 @@
import { Context, Next } from 'hono'; import { Context, Next } from 'hono';
import jwt from 'jsonwebtoken';
import config from '../config';
import supabase from '../utils/supabase'; import supabase from '../utils/supabase';
// Interface for JWT payload // Middleware to verify Supabase token
interface JwtPayload {
sub: string;
email: string;
iat: number;
exp: number;
}
// Middleware to verify JWT token
export const authMiddleware = async (c: Context, next: Next) => { export const authMiddleware = async (c: Context, next: Next) => {
try { try {
// Get authorization header // Get authorization header
@@ -25,41 +15,24 @@ export const authMiddleware = async (c: Context, next: Next) => {
const token = authHeader.split(' ')[1]; const token = authHeader.split(' ')[1];
try { try {
// 验证 JWT token // 验证 Supabase token
const decoded = jwt.verify(token, config.jwt.secret) as JwtPayload; const { data, error } = await supabase.auth.getUser(token);
// 特殊处理 Swagger 测试 token if (error || !data.user) {
if (decoded.sub === 'swagger-test-user' && decoded.email === 'swagger@test.com') { return c.json({ error: 'Unauthorized: Invalid token' }, 401);
// 为 Swagger 测试设置一个模拟用户
c.set('user', {
id: 'swagger-test-user',
email: 'swagger@test.com',
name: 'Swagger Test User'
});
// 继续到下一个中间件或路由处理器
await next();
return;
} }
// 设置用户信息到上下文 // 设置用户信息到上下文
c.set('user', { c.set('user', {
id: decoded.sub, id: data.user.id,
email: decoded.email email: data.user.email || ''
}); });
// 继续到下一个中间件或路由处理器 // 继续到下一个中间件或路由处理器
await next(); await next();
} catch (jwtError) { } catch (error) {
if (jwtError instanceof jwt.JsonWebTokenError) { console.error('Token verification error:', error);
return c.json({ error: 'Unauthorized: Invalid token' }, 401); return c.json({ error: 'Unauthorized: Invalid token' }, 401);
}
if (jwtError instanceof jwt.TokenExpiredError) {
return c.json({ error: 'Unauthorized: Token expired' }, 401);
}
throw jwtError;
} }
} catch (error) { } catch (error) {
console.error('Auth middleware error:', error); console.error('Auth middleware error:', error);
@@ -67,21 +40,23 @@ export const authMiddleware = async (c: Context, next: Next) => {
} }
}; };
// Generate JWT token // Get Supabase token
export const generateToken = (userId: string, email: string): string => { export const getSupabaseToken = async (email: string, password: string) => {
const secret = config.jwt.secret; try {
const expiresIn = config.jwt.expiresIn; const { data, error } = await supabase.auth.signInWithPassword({
return jwt.sign(
{
sub: userId,
email, email,
}, password
secret, });
{
expiresIn, if (error || !data.session) {
return null;
} }
);
return data.session.access_token;
} catch (error) {
console.error('Error getting Supabase token:', error);
return null;
}
}; };
// Verify Supabase token // Verify Supabase token

View File

@@ -1,7 +1,6 @@
import { Hono } from 'hono'; import { Hono } from 'hono';
import { generateToken, verifySupabaseToken } from '../middlewares/auth'; import { verifySupabaseToken, getSupabaseToken } from '../middlewares/auth';
import supabase from '../utils/supabase'; import supabase from '../utils/supabase';
import jwt from 'jsonwebtoken';
const authRouter = new Hono(); const authRouter = new Hono();
@@ -45,8 +44,12 @@ authRouter.post('/register', async (c) => {
return c.json({ error: profileError.message }, 500); return c.json({ error: profileError.message }, 500);
} }
// Generate JWT token // 直接使用 Supabase 的 session token
const token = generateToken(authData.user.id, authData.user.email!); const sessionToken = authData.session?.access_token;
if (!sessionToken) {
return c.json({ error: 'Failed to generate token' }, 500);
}
return c.json({ return c.json({
message: 'User registered successfully', message: 'User registered successfully',
@@ -55,7 +58,7 @@ authRouter.post('/register', async (c) => {
email: authData.user.email, email: authData.user.email,
name, name,
}, },
token, token: sessionToken,
}, 201); }, 201);
} catch (error) { } catch (error) {
console.error('Registration error:', error); console.error('Registration error:', error);
@@ -77,8 +80,12 @@ authRouter.post('/login', async (c) => {
return c.json({ error: error.message }, 400); return c.json({ error: error.message }, 400);
} }
// 使用与 authMiddleware 一致的方式创建 JWT if (!data.session) {
const token = generateToken(data.user.id, data.user.email || ''); return c.json({ error: 'Failed to login' }, 500);
}
// 直接使用 Supabase 的 session token
const token = data.session.access_token;
// 只返回必要的用户信息和令牌 // 只返回必要的用户信息和令牌
return c.json({ return c.json({
@@ -132,22 +139,21 @@ authRouter.post('/refresh-token', async (c) => {
return c.json({ error: 'No token provided' }, 401); return c.json({ error: 'No token provided' }, 401);
} }
// 验证当前token // 使用 Supabase 刷新 token
const user = await verifySupabaseToken(token); const { data, error } = await supabase.auth.refreshSession({
refresh_token: token
});
if (!user) { if (error || !data.session || !data.user) {
return c.json({ error: 'Invalid token' }, 401); return c.json({ error: 'Invalid token' }, 401);
} }
// 生成新token
const newToken = generateToken(user.id, user.email || '');
return c.json({ return c.json({
message: 'Token refreshed successfully', message: 'Token refreshed successfully',
token: newToken, token: data.session.access_token,
user: { user: {
id: user.id, id: data.user.id,
email: user.email, email: data.user.email,
}, },
}); });
} catch (error) { } catch (error) {

View File

@@ -1,7 +1,6 @@
import { swaggerUI } from '@hono/swagger-ui' import { swaggerUI } from '@hono/swagger-ui'
import { Hono } from 'hono' import { Hono } from 'hono'
import jwt from 'jsonwebtoken' import supabase from '../utils/supabase'
import config from '../config'
// 创建 OpenAPI 规范 // 创建 OpenAPI 规范
export const openAPISpec = { export const openAPISpec = {
@@ -1839,26 +1838,52 @@ export const createSwaggerUI = () => {
// 添加临时的 token 生成端点,仅用于 Swagger 测试 // 添加临时的 token 生成端点,仅用于 Swagger 测试
app.get('/api/swagger/token', async (c) => { app.get('/api/swagger/token', async (c) => {
try { try {
// 创建一个临时 token与 authMiddleware 中的验证方式一致 // Swagger 测试用户的凭据
const token = jwt.sign( const email = 'swagger@test.com';
{ const password = 'swagger-test-password';
sub: 'swagger-test-user',
email: 'swagger@test.com', // 尝试使用 Supabase 认证
}, const { data, error } = await supabase.auth.signInWithPassword({
config.jwt.secret, email,
{ password
expiresIn: '1h', });
if (error || !data.session) {
// 如果登录失败,可能需要先创建测试用户
console.log('尝试创建 Swagger 测试用户...');
// 尝试创建测试用户
await supabase.auth.admin.createUser({
email,
password,
email_confirm: true,
});
// 再次尝试登录
const loginResult = await supabase.auth.signInWithPassword({
email,
password
});
if (loginResult.error || !loginResult.data.session) {
return c.json({ error: '无法创建测试用户凭据', details: loginResult.error?.message }, 500);
} }
);
return c.json({
message: '已创建 Swagger 测试用户并生成 token',
token: loginResult.data.session.access_token,
usage: '在 Authorize 对话框中输入: Bearer [token]'
});
}
return c.json({ return c.json({
message: '此 token 仅用于 Swagger UI 测试', message: '此 token 仅用于 Swagger UI 测试',
token, token: data.session.access_token,
usage: '在 Authorize 对话框中输入: Bearer [token]' usage: '在 Authorize 对话框中输入: Bearer [token]'
}); });
} catch (error) { } catch (error) {
console.error('Error generating swagger token:', error); console.error('Error generating swagger token:', error);
return c.json({ error: 'Failed to generate token' }, 500); return c.json({ error: '生成 token 失败', details: error instanceof Error ? error.message : String(error) }, 500);
} }
}); });