개발여행
Clerk metadata로 어드민 계정 롤 부여하기 본문
Clerk 서비스를 사용하면 간편하게 인증 플로우를 구현할 수 있는 것은 물론, Clerk가 관리해주는 유저 계정에 metadata를 추가해 일반 유저와 어드민 유저를 분리할 수도 있다.
관리자페이지를 작업하면서 이것저것 알아본 김에 Clerk 미들웨어를 통해 유저의 metadata를 확인하고, 어드민 유저만 특정 페이지에 접근할 수 있도록 구현하는 방법을 정리해봤다.
유저 계정에 metadata 추가
Metadata는 API를 사용하거나 대시보드에 접속해서 수동으로 설정할 수 있다. 이번에는 관리자사이트의 특성상 사용자 계정과 관련된 불필요한 사고를 방지하고자 수동으로 metadata를 추가하는 방법을 선택했다.
Public과 unsafe metadata는 클라이언트에서 접근할 수 있는 방면 private metadata는 서버에서만 접근할 수 있도록 되어있다. Next.js 프레임워크를 선택한 나 같은 경우 서버 함수에서만 auth 로직을 돌리도록 구현했기 때문에 private metadata에 { "role": "admin" } 객체를 넣어줬다.
미들웨어 적용
아래는 미들웨어를 Clerk 미들웨어 하나만 적용한다고 했을 때 바로 사용할 수 있는 코드다. (다른 미들웨어도 함께 사용해야 할 경우 공식 문서 참고) 이 미들웨어에서는 유저 정보의 metadata를 확인해 role이 admin일 경우에만 페이지 접근을 허용한다.
import { clerkClient, clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isProtectedRoute = createRouteMatcher(["/users(.*)"]);
export default clerkMiddleware(async (auth, req) => {
if (isProtectedRoute(req)) {
try {
const { userId } = auth();
const userData = await clerkClient.users.getUser(userId ?? "");
auth().protect(() => userData.privateMetadata.role === "admin");
} catch (e) {
console.log(e);
}
auth().protect();
}
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
권한이 없는 유저로부터 보호할 페이지는 Clerk에서 제공하는 createRouteMatcher() 함수에 대상 path들을 배열로 전달해 지정한다. 이때 리턴되는 isProtectedRoute() 함수는 미들웨어 함수 내에서 사용해 보호된 페이지인지 아닌지를 확인한다.
clerkMiddleware()에 전달하는 함수는 auth() 메소드와 HTTP 요청을 인자로 받는다. 로그인한 유저가 아닐 경우 auth() 함수에서 예외가 발생하기 때문에 try-catch 블럭에서 유저 데이터를 읽고 metadata를 체크하도록 했다.
페이지 접근을 제한할 땐 auth().protect() 함수를 호출한다. 이 함수에는 boolean 값을 리턴하는 또다른 함수를 인자로 전달할 수 있어서, 어드민 계정인지를 체크하는 조건부를 넣어줬다. 아무것도 전달하지 않을 경우 조건없이 모든 유저들의 접근을 차단하게 된다.
'Frontend' 카테고리의 다른 글
Vue SFC 컴포넌트의 CSS 적용 방식 (0) | 2024.06.12 |
---|---|
Vue 배우기 (3) (0) | 2024.06.06 |
Next.js: Clerk로 로그인 플로우 구현 (0) | 2024.05.31 |
Vue 배우기 (2) (0) | 2024.05.30 |
Vue 배우기 (1) (0) | 2024.05.29 |