1
0
forked from baron/baron-sso

custom claim 권한체크 확인

This commit is contained in:
2026-06-11 08:29:25 +09:00
parent 839ca9d407
commit 4d77060b5d
79 changed files with 4268 additions and 670 deletions

View File

@@ -84,6 +84,7 @@ interface IdTokenClaimItem {
key: string;
value: string;
valueType: ClaimValueType;
nullable: boolean;
readPermission: CustomClaimPermission;
writePermission: CustomClaimPermission;
}
@@ -169,6 +170,7 @@ function createIdTokenClaimItem(id: string): IdTokenClaimItem {
key: "",
value: "",
valueType: "text",
nullable: false,
readPermission: "admin_only",
writePermission: "admin_only",
};
@@ -217,6 +219,7 @@ function readIdTokenClaimsMetadata(
key: keyValue,
value: valueValue,
valueType: valueTypeValue,
nullable: record.nullable === true,
readPermission: isCustomClaimPermission(record.readPermission)
? record.readPermission
: "admin_only",
@@ -231,8 +234,12 @@ function readIdTokenClaimsMetadata(
function normalizeClaimPreviewValue(
value: string,
valueType: ClaimValueType,
nullable: boolean,
): unknown {
const trimmed = value.trim();
if (nullable && trimmed === "") {
return null;
}
if (valueType === "number") {
if (trimmed === "") return "";
const parsed = Number(trimmed);
@@ -284,7 +291,11 @@ function buildIdTokenClaimsPreview(
continue;
}
rpClaims[key] = normalizeClaimPreviewValue(item.value, item.valueType);
rpClaims[key] = normalizeClaimPreviewValue(
item.value,
item.valueType,
item.nullable,
);
}
if (Object.keys(rpClaims).length > 0) {
@@ -755,6 +766,25 @@ function ClientGeneralPage() {
);
};
const setIdTokenClaimPermissionAllowed = (
id: string,
field: "readPermission" | "writePermission",
allowed: boolean,
) => {
const permission = allowed ? "user_and_admin" : "admin_only";
setIdTokenClaims((current) =>
current.map((claim) => {
if (claim.id !== id) {
return claim;
}
return {
...claim,
[field]: permission,
};
}),
);
};
const removeIdTokenClaim = (id: string) => {
setIdTokenClaims((current) => current.filter((claim) => claim.id !== id));
};
@@ -1090,6 +1120,7 @@ function ClientGeneralPage() {
return createClient(payload);
}
await queryClient.cancelQueries({ queryKey: ["client", clientId] });
const updated = await updateClient(clientId as string, payload);
if (status !== initialStatus) {
await updateClientStatus(clientId as string, status);
@@ -1097,6 +1128,10 @@ function ClientGeneralPage() {
return updated;
},
onSuccess: (result) => {
const resultClientId = result?.client?.id ?? clientId;
if (resultClientId) {
queryClient.setQueryData(["client", resultClientId], result);
}
queryClient.invalidateQueries({ queryKey: ["clients"] });
if (status !== initialStatus) {
setInitialStatus(status);
@@ -2109,20 +2144,26 @@ function ClientGeneralPage() {
</th>
<th className="px-4 py-3 text-left font-bold">
{t(
"ui.dev.clients.general.id_token_claims.table.read_permission",
"ui.dev.clients.general.id_token_claims.table.nullable",
"Nullable",
)}
</th>
<th className="px-4 py-3 text-left font-bold">
{t(
"ui.dev.clients.general.id_token_claims.table.read_user_allowed",
"Read",
)}
</th>
<th className="px-4 py-3 text-left font-bold">
{t(
"ui.dev.clients.general.id_token_claims.table.write_permission",
"ui.dev.clients.general.id_token_claims.table.write_user_allowed",
"Write",
)}
</th>
<th className="px-4 py-3 text-left font-bold">
{t(
"ui.dev.clients.general.id_token_claims.table.value",
"Value",
"ui.dev.clients.general.id_token_claims.table.default_value",
"Default Value",
)}
</th>
<th className="px-4 py-3 text-right font-bold">
@@ -2227,66 +2268,65 @@ function ClientGeneralPage() {
</select>
</td>
<td className="px-4 py-3 align-top">
<select
value={claim.readPermission}
onChange={(e) =>
updateIdTokenClaim(
claim.id,
"readPermission",
e.target.value as CustomClaimPermission,
)
}
aria-label={t(
"ui.dev.clients.general.id_token_claims.read_permission_label",
"읽기 권한",
)}
className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
disabled={isGeneralSettingsReadOnly}
>
<option value="admin_only">
{t(
"ui.common.custom_claim_permission.admin_only",
"관리자만 가능",
<div className="flex h-9 items-center">
<Switch
checked={claim.nullable}
onCheckedChange={(checked) =>
updateIdTokenClaim(
claim.id,
"nullable",
checked,
)
}
aria-label={t(
"ui.dev.clients.general.id_token_claims.nullable_label",
"Nullable",
)}
</option>
<option value="user_and_admin">
{t(
"ui.common.custom_claim_permission.user_and_admin",
"사용자 및 관리자 가능",
)}
</option>
</select>
disabled={isGeneralSettingsReadOnly}
/>
</div>
</td>
<td className="px-4 py-3 align-top">
<select
value={claim.writePermission}
onChange={(e) =>
updateIdTokenClaim(
claim.id,
"writePermission",
e.target.value as CustomClaimPermission,
)
}
aria-label={t(
"ui.dev.clients.general.id_token_claims.write_permission_label",
"쓰기 권한",
)}
className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
disabled={isGeneralSettingsReadOnly}
>
<option value="admin_only">
{t(
"ui.common.custom_claim_permission.admin_only",
"관리자만 가능",
<div className="flex h-9 items-center">
<Switch
checked={
claim.readPermission === "user_and_admin"
}
onCheckedChange={(checked) =>
setIdTokenClaimPermissionAllowed(
claim.id,
"readPermission",
checked,
)
}
aria-label={t(
"ui.dev.clients.general.id_token_claims.read_user_allowed_label",
"Read 사용자 허용",
)}
</option>
<option value="user_and_admin">
{t(
"ui.common.custom_claim_permission.user_and_admin",
"사용자 및 관리자 가능",
disabled={isGeneralSettingsReadOnly}
/>
</div>
</td>
<td className="px-4 py-3 align-top">
<div className="flex h-9 items-center">
<Switch
checked={
claim.writePermission === "user_and_admin"
}
onCheckedChange={(checked) =>
setIdTokenClaimPermissionAllowed(
claim.id,
"writePermission",
checked,
)
}
aria-label={t(
"ui.dev.clients.general.id_token_claims.write_user_allowed_label",
"Write 사용자 허용",
)}
</option>
</select>
disabled={isGeneralSettingsReadOnly}
/>
</div>
</td>
<td className="px-4 py-3 align-top">
<Input
@@ -2301,7 +2341,7 @@ function ClientGeneralPage() {
className="h-9 font-mono text-xs"
placeholder={t(
"ui.dev.clients.general.id_token_claims.value_placeholder",
"Enter the claim value",
"Enter the default value",
)}
disabled={isGeneralSettingsReadOnly}
/>