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 { getAuthorizeUrl } from "@/lib/oauth/authorize-url";
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(
oauth: string,
userId: string,
clientId: string,
scope: string,
) {
try {
// 检查客户端是否限制了允许的用户
const client = await prisma.client.findUnique({
where: { id: clientId },
select: { allowedUsers: true, name: true, enabled: true },
});
if (!client) {
return { error: "应用不存在" };
// 获取当前登录用户
const currentUser = await getCurrentUser();
if (!currentUser?.id) {
return { error: "请先登录" };
}
if (!client.enabled) {
return { error: "该应用已被禁用" };
}
// 如果设置了允许的用户列表,检查当前用户是否在列表中
if (client.allowedUsers.length > 0) {
// 获取用户信息
const user = await prisma.user.findUnique({
where: { id: userId },
where: { id: currentUser.id },
select: { username: true },
});
@ -38,24 +84,61 @@ export async function handleAuthorizeAction(
return { error: "用户不存在" };
}
if (!client.allowedUsers.includes(user.username)) {
return {
error: "您没有权限使用此应用",
};
}
// 检查平台级权限
const platformAuth = await checkPlatformAuthorization(
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({
userId,
userId: currentUser.id,
clientId,
scope,
enabled: true, // 新授权默认启用
lastUsedAt: new Date(), // 首次授权时间作为最后使用时间
enabled: true,
lastUsedAt: new Date(),
});
}
// 处理重定向
const oauthParams = new URLSearchParams(atob(oauth));
const redirectUrl = getAuthorizeUrl(oauthParams);
// 刷新相关页面
revalidatePath("/dashboard");

View File

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