only use supabase token
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user