refactor: Enhance authorization flow with improved permission checks and user context

- Separate platform and application-level authorization checks
- Use current user session for authorization instead of passing user ID
- Add detailed permission validation with specific error messages
- Simplify authorization record creation and update logic
- Remove redundant client and user checks
This commit is contained in:
wood chen 2025-02-20 03:03:49 +08:00
parent 3782ec8ca0
commit 493ad7136f
2 changed files with 116 additions and 34 deletions

View File

@ -5,32 +5,78 @@ import { revalidatePath } from "next/cache";
import { createAuthorization } from "@/lib/dto/authorization"; import { createAuthorization } from "@/lib/dto/authorization";
import { getAuthorizeUrl } from "@/lib/oauth/authorize-url"; import { getAuthorizeUrl } from "@/lib/oauth/authorize-url";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
import { getCurrentUser } from "@/lib/session";
// 检查平台级权限
async function checkPlatformAuthorization(clientId: string, userId: string) {
// 检查应用是否被平台禁用
const client = await prisma.client.findUnique({
where: { id: clientId },
select: { enabled: true },
});
if (!client) {
return { allowed: false, error: "应用不存在" };
}
if (!client.enabled) {
return { allowed: false, error: "该应用已被平台管理员禁用" };
}
// 检查用户授权是否被平台禁用
const existingAuth = await prisma.authorization.findUnique({
where: {
userId_clientId: { userId, clientId },
},
select: { enabled: true },
});
if (existingAuth && !existingAuth.enabled) {
return { allowed: false, error: "您的授权已被平台管理员禁用" };
}
return { allowed: true };
}
// 检查应用级权限
async function checkApplicationAuthorization(
clientId: string,
username: string,
) {
const client = await prisma.client.findUnique({
where: { id: clientId },
select: { allowedUsers: true, name: true },
});
if (!client) {
return { allowed: false, error: "应用不存在" };
}
const isAllowedByOwner =
client.allowedUsers.length === 0 || client.allowedUsers.includes(username);
if (!isAllowedByOwner) {
return { allowed: false, error: "此应用不允许您登录,请联系应用所有者" };
}
return { allowed: true };
}
export async function handleAuthorizeAction( export async function handleAuthorizeAction(
oauth: string, oauth: string,
userId: string,
clientId: string, clientId: string,
scope: string, scope: string,
) { ) {
try { try {
// 检查客户端是否限制了允许的用户 // 获取当前登录用户
const client = await prisma.client.findUnique({ const currentUser = await getCurrentUser();
where: { id: clientId }, if (!currentUser?.id) {
select: { allowedUsers: true, name: true, enabled: true }, return { error: "请先登录" };
});
if (!client) {
return { error: "应用不存在" };
} }
if (!client.enabled) { // 获取用户信息
return { error: "该应用已被禁用" };
}
// 如果设置了允许的用户列表,检查当前用户是否在列表中
if (client.allowedUsers.length > 0) {
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { id: userId }, where: { id: currentUser.id },
select: { username: true }, select: { username: true },
}); });
@ -38,24 +84,61 @@ export async function handleAuthorizeAction(
return { error: "用户不存在" }; return { error: "用户不存在" };
} }
if (!client.allowedUsers.includes(user.username)) { // 检查平台级权限
return { const platformAuth = await checkPlatformAuthorization(
error: "您没有权限使用此应用", clientId,
}; currentUser.id,
} );
if (!platformAuth.allowed) {
return { error: platformAuth.error };
} }
const oauthParams = new URLSearchParams(atob(oauth)); // 检查应用级权限
const redirectUrl = getAuthorizeUrl(oauthParams); const appAuth = await checkApplicationAuthorization(
clientId,
user.username,
);
if (!appAuth.allowed) {
return { error: appAuth.error };
}
// 保存授权 // 检查或创建授权记录
const existingAuth = await prisma.authorization.findUnique({
where: {
userId_clientId: {
userId: currentUser.id,
clientId,
},
},
});
if (existingAuth) {
// 更新最后使用时间
await prisma.authorization.update({
where: {
userId_clientId: {
userId: currentUser.id,
clientId,
},
},
data: {
lastUsedAt: new Date(),
},
});
} else {
// 创建新的授权记录
await createAuthorization({ await createAuthorization({
userId, userId: currentUser.id,
clientId, clientId,
scope, scope,
enabled: true, // 新授权默认启用 enabled: true,
lastUsedAt: new Date(), // 首次授权时间作为最后使用时间 lastUsedAt: new Date(),
}); });
}
// 处理重定向
const oauthParams = new URLSearchParams(atob(oauth));
const redirectUrl = getAuthorizeUrl(oauthParams);
// 刷新相关页面 // 刷新相关页面
revalidatePath("/dashboard"); revalidatePath("/dashboard");

View File

@ -60,7 +60,6 @@ export function AuthorizationCard({
setError(null); setError(null);
const result = await handleAuthorizeAction( const result = await handleAuthorizeAction(
oauthParams, oauthParams,
client.userId,
client.id, client.id,
permissions[0].id, permissions[0].id,
); );