sori.studio

워드프레스 로그인 & 글 작성 직접 구현하기 (JWT 인증)

📘 워드프레스 REST API를 이용해서 나만의 사이트 만들기 - 2편

워드프레스로 로그인 & 글쓰기 직접 구현하기 (JWT 인증 사용)

 

지난 글에서는 워드프레스 REST API를 이용해서 등록된 게시물을 가져와서 웹사이트에 표시하는 걸 해봤다.
REST API가 잘 동작하는것을 확인했으니 이제 이것을 이용해서 원하는 사이트를 만들어 볼 차례이다.

 

무엇을 만들 것인가

이번 프로젝트는 트위터처럼 짧고 간단한 글을 남기는 구조를 목표로 하고 있다.
그 이유는, 나에게 있었던 일이나 게임 플레이 기록, 구매한 물건 등 다양한 일상들을 블로그 글이라고 하기엔 애매할 정도로 짧게 남기고 싶었기 때문이다.
“언제, 어떤 일이 있었다” 정도만 빠르게 기록할 수 있는 형식을 고민하다가, 트위터처럼 가볍게 글을 쓸 수 있는 구조가 가장 적합하다고 느꼈다.

그래서 기존 블로그처럼 “글 작성 페이지로 이동 → 제목 입력 → 본문 작성” 같은 흐름은 아예 없다.
하나의 화면(index.html) 안에서, 상단에는 글 작성 공간이, 하단에는 작성된 글 목록이 바로 이어지는 구조로 만들어볼 것이다.
기왕 트위터처럼 만들기로 했으니 다른 사람들도 글을 쓸수 있도록 해보면 어떨까 한다.

그래서 index.html을 열면 로그인한 사용자라면 바로 글을 쓸 수 있어야 하고, 로그인하지 않은 상태라면 글쓰기를 막고 로그인 페이지로 보내는 방식으로 구성할 예정이다.

 

 

인증은 꼭 필요하다

REST API로 글을 작성하거나 수정하려면 인증이 필요하다.
그래서 이번 글에서는 JWT 토큰 기반 인증을 도입해서 로그인 → 토큰 발급 → 글 작성 요청 까지 연결하는 흐름을 만든다.

 

 

플러그인 설치: JWT Authentication for WP REST API

워드프레스 관리자 페이지에서 이 플러그인을 설치한다: JWT Authentication for WP REST API

 

설치 후 아래 설정들을 추가해야 한다.

 

wp-config.php에 추가:

define('JWT_AUTH_SECRET_KEY', '적당히_복잡한_비밀키');
define('JWT_AUTH_CORS_ENABLE', true);

여기서 비밀키는 https://randomkeygen.com/ 같은 사이트를 이용해서 가져와도 좋고, 직접 'e2f7c6b4a8d9e1f0b3c4d5f6e7f8g9h0i1j2k3l4m5n6o7p8'와 같은 16진수 형식의 랜덤한 값을 지정해도 된다.

 

.htaccess (Apache 사용 시):

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

 

 

로그인 요청: 토큰 받아오기

로그인 폼에서 입력한 정보로 아래 API에 요청을 보내면 된다:

POST /wp-json/jwt-auth/v1/token

 

 

요청 바디는 이렇게:

{
  "username": "아이디",
  "password": "비밀번호"
}

 

응답으로는 이렇게 생긴 토큰이 온다:

{
  "token": "eyJ0eXAiOiJKV1QiLCJhbGci...",
  "user_email": "example@email.com",
  "user_nicename": "홍길동",
  ...
}

 

여기서 이 token만 뽑아서 localStorage에 저장해두면 된다.

 

 

로그인 화면(login.html)의 스크립트:

async function login() {
  const username = usernameInput.value;
  const password = passwordInput.value;

  const response = await fetch(
    'https://myDomain.com/wp-json/jwt-auth/v1/token',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password }),
    },
  );

  const result = await response.json();

  if (result.token) {
    localStorage.setItem('jwt_token', result.token); // 토큰 저장
    document.getElementById('message').innerText = '로그인 성공!';
    window.location.href = 'index.html'; // 메인 페이지로 이동
  } else {
    document.getElementById('message').innerText = '로그인 실패: ' + result.message;
  }
}

 

 

index.html에서 토큰 검사하기

index.html을 열었을 때, 토큰이 없다면 바로 login.html로 보내버린다.
HTML로 웹을 구현한다면 매 페이지 이 동작이 필요하다.

const token = localStorage.getItem('jwt_token');
if (!token) {
  window.location.href = 'login.html';
}

 

 

게시물 작성하기

다시한번 정리하는 목표로 하고있는 index.html 구조를 요약해본다.

  • 글 작성 영역: 상단에 바로 입력
  • 이미지 업로드도 여기서 처리 (이번 내용에서는 제외)
  • 게시하기 버튼을 누르면 REST API로 POST 요청

글 작성을 위한 별도 페이지는 없다.
트위터같은 느낌의 메인 화면에서 모든 걸 처리한다.

 

 

 

글 작성 영역(index.html):

<textarea 
  id="postContent" placeholder="무슨 일이 일어나고 있나요?" 
  rows="3" style="width:100%;">
</textarea>
<button onclick="submitPost()">게시하기</button>

 

글 작성 요청(index.js) 함수:

async function submitPost() {
  const content = document.getElementById('postContent').value;
  if (!content.trim()) return;

  const response = await fetch(apiUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}` // JWT 인증 추가
    },
    body: JSON.stringify({
      title: '새 게시물',
      content: content,
      status: 'publish'
    })
  });

  if (response.ok) {
    document.getElementById('postContent').value = '';
    fetchPosts();
  } else {
    alert('게시 실패! 로그인 상태를 확인하세요.');
  }
}

 

 

🔖 참고: 워드프레스 status 값 종류

 

  • publish: 공개 글. 누구나 볼 수 있음.
  • draft: 임시 글. 로그인한 작성자만 볼 수 있음.
  • pending: 검토 대기 글. 관리자 승인 후 공개되는 구조에 사용됨.
  • private: 비공개 글. 로그인한 작성자 또는 관리자만 볼 수 있음.
  • future: 예약 발행. date 필드를 함께 설정해야 함.
  • trash: 휴지통으로 이동된 글.
  • inherit: 첨부 파일 등에 사용되는 내부용 상태. 직접 쓸 일은 거의 없음.
  • auto-draft: 자동 저장된 초안. 워드프레스 내부에서 사용. 일반적으로 사용 안 함.

 

예시: 예약발행

{
  "title": "예약된 글",
  "content": "이 글은 나중에 자동으로 공개됩니다.",
  "status": "future",
  "date": "2025-04-10T10:00:00"
}

 

필요에 따라 버튼 UI를 다르게 구성하여 "임시 저장" 버튼 누르면 "status": "draft"로 보내고, "발행하기" 버튼 누르면 "publish"로 보내는 식으로 게시물을 작성할 수 있지만 지금 내가 만들려고하는 사이트에서는 이런 기능이 필요 없기에 사용하지는 않을 예정.