Sonamu에서 사용자 인증을 설정하는 방법을 알아봅니다. Sonamu는 better-auth 를 기반으로 한 통합 인증 시스템을 제공합니다.
인증 시스템 개요
better-auth 통합 검증된 인증 라이브러리 이메일/비밀번호, 소셜 로그인
자동 엔티티 생성 CLI로 엔티티 자동 생성 User, Session, Account, Verification
Context 기반 요청마다 사용자 정보 Sonamu.getContext()
Guards 시스템 선언적 권한 제어 @api guards 옵션
빠른 시작
1. 인증 엔티티 생성
better-auth가 필요로 하는 엔티티들을 자동으로 생성합니다:
pnpm sonamu auth generate
이 명령어는 4개의 엔티티를 생성합니다:
엔티티 테이블 설명 User users 사용자 정보 (id, name, email, email_verified, image) Session sessions 세션 정보 (id, token, expires_at, user_id) Account accounts 소셜 계정 연결 (id, provider_id, access_token, user_id) Verification verifications 이메일 인증 등 (id, identifier, value, expires_at)
기존 엔티티가 있으면 누락된 필드만 추가됩니다. 필드 타입이 변경된 경우 자동으로 업데이트됩니다.
2. 마이그레이션 실행
엔티티 생성 후 마이그레이션을 실행합니다:
pnpm sonamu migrate generate
pnpm sonamu migrate run
3. 인증 설정
sonamu.config.ts에서 인증을 활성화합니다:
// sonamu.config.ts
import type { SonamuConfig } from "sonamu" ;
export default {
// ... 다른 설정들
server: {
auth: {
emailAndPassword: { enabled: true },
},
} ,
} satisfies SonamuConfig ;
이것으로 기본적인 이메일/비밀번호 인증이 활성화됩니다.
API 엔드포인트
better-auth가 제공하는 API 엔드포인트들이 자동으로 등록됩니다:
경로 메서드 설명 /api/auth/sign-up/emailPOST 이메일 회원가입 /api/auth/sign-in/emailPOST 이메일 로그인 /api/auth/sign-outPOST 로그아웃 /api/auth/get-sessionGET 현재 세션 조회
Context에서 사용자 정보 접근
인증된 사용자 정보는 Context를 통해 접근합니다:
import { Sonamu } from "sonamu" ;
class UserModelClass extends BaseModel {
@ api ({ httpMethod: "GET" , guards: [ "user" ] })
async me () : Promise < UserSubsetA | null > {
const { user , session } = Sonamu . getContext ();
if ( ! user ) return null ;
// user.id, user.email, user.name 등 접근 가능
return this . findById ( "A" , user . id );
}
}
AuthContext 타입
type AuthContext = {
/** 현재 로그인한 사용자 (null이면 미인증) */
user : User | null ;
/** 현재 세션 정보 (null이면 미인증) */
session : Session | null ;
};
User와 Session 타입은 better-auth에서 제공합니다.
Guards를 통한 접근 제어
기본 Guard 사용
class UserModelClass extends BaseModel {
// 로그인 필수
@ api ({ httpMethod: "GET" , guards: [ "user" ] })
async getProfile () {
const { user } = Sonamu . getContext ();
return { userId: user . id };
}
// 관리자 권한 필요
@ api ({ httpMethod: "DELETE" , guards: [ "admin" ] })
async deleteUser ( id : string ) {
// 관리자만 실행 가능
}
}
guardHandler 구현
Guard 로직은 sonamu.config.ts의 guardHandler에서 구현합니다:
// sonamu.config.ts
import { Sonamu } from "sonamu" ;
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
},
apiConfig: {
guardHandler : ( guard , request , api ) => {
const { user } = Sonamu . getContext ();
switch ( guard ) {
case "user" :
if ( ! user ) {
throw new Error ( "로그인이 필요합니다" );
}
break ;
case "admin" :
// User 엔티티에 role 필드 추가 필요
if ( ! user || ( user as any ). role !== "admin" ) {
throw new Error ( "관리자만 접근 가능합니다" );
}
break ;
case "query" :
// 모든 사용자 허용
break ;
}
},
},
} ,
} satisfies SonamuConfig ;
소셜 로그인 설정
Google 로그인
// sonamu.config.ts
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
socialProviders: {
google: {
clientId: process . env . GOOGLE_CLIENT_ID ! ,
clientSecret: process . env . GOOGLE_CLIENT_SECRET ! ,
},
},
},
} ,
} satisfies SonamuConfig ;
GitHub 로그인
// sonamu.config.ts
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process . env . GITHUB_CLIENT_ID ! ,
clientSecret: process . env . GITHUB_CLIENT_SECRET ! ,
},
},
},
} ,
} satisfies SonamuConfig ;
사용자 역할 추가
better-auth의 기본 User 엔티티에는 role 필드가 없습니다. 권한 기반 인증이 필요하면 User 엔티티에 직접 추가하세요:
1. Sonamu UI에서 필드 추가
User 엔티티에 role 필드를 추가합니다:
이름: role
타입: string
기본값: "user"
2. Enum 추가 (선택사항)
{
"enums" : {
"UserRole" : {
"user" : "일반 사용자" ,
"admin" : "관리자" ,
"manager" : "매니저"
}
}
}
3. guardHandler에서 역할 확인
guardHandler : ( guard , request , api ) => {
const { user } = Sonamu . getContext ();
if ( guard === "admin" ) {
if ( ! user || ( user as any ). role !== "admin" ) {
throw new Error ( "관리자 권한이 필요합니다" );
}
}
},
클라이언트 통합
React에서 사용
import { createAuthClient } from "better-auth/react" ;
export const authClient = createAuthClient ({
baseURL: "http://localhost:4000/api/auth" ,
});
// 회원가입
await authClient . signUp . email ({
email: "user@example.com" ,
password: "password123" ,
name: "홍길동" ,
});
// 로그인
await authClient . signIn . email ({
email: "user@example.com" ,
password: "password123" ,
});
// 로그아웃
await authClient . signOut ();
// 현재 세션 조회
const session = await authClient . getSession ();
필드 매핑
better-auth는 camelCase를 사용하지만, Sonamu는 snake_case를 사용합니다. 다음 필드들이 자동으로 매핑됩니다:
better-auth Sonamu emailVerifiedemail_verifiedcreatedAtcreated_atuserIduser_idexpiresAtexpires_at
체크리스트
인증 설정 후 확인 사항:
다음 단계