워드프레스로 로그인 & 글쓰기 직접 구현하기 (JWT 인증 사용)
지난 글에서는 워드프레스 REST API를 이용해서 등록된 게시물을 가져와서 웹사이트에 표시하는 걸 해봤다.REST API가 잘 동작하는것을 확인했으니 이제 이것을 이용해서 원하는 사이트를 만들어 볼 차례이다.
이번 프로젝트는 트위터처럼 짧고 간단한 글을 남기는 구조를 목표로 하고 있다.그 이유는, 나에게 있었던 일이나 게임 플레이 기록, 구매한 물건 등 다양한 일상들을 블로그 글이라고 하기엔 애매할 정도로 짧게 남기고 싶었기 때문이다.“언제, 어떤 일이 있었다” 정도만 빠르게 기록할 수 있는 형식을 고민하다가, 트위터처럼 가볍게 글을 쓸 수 있는 구조가 가장 적합하다고 느꼈다.그래서 기존 블로그처럼 “글 작성 페이지로 이동 → 제목 입력 → 본문 작성” 같은 흐름은 아예 없다.하나의 화면(index.html) 안에서, 상단에는 글 작성 공간이, 하단에는 작성된 글 목록이 바로 이어지는 구조로 만들어볼 것이다.기왕 트위터처럼 만들기로 했으니 다른 사람들도 글을 쓸수 있도록 해보면 어떨까 한다.그래서 index.html을 열면 로그인한 사용자라면 바로 글을 쓸 수 있어야 하고, 로그인하지 않은 상태라면 글쓰기를 막고 로그인 페이지로 보내는 방식으로 구성할 예정이다.
REST API로 글을 작성하거나 수정하려면 인증이 필요하다.그래서 이번 글에서는 JWT 토큰 기반 인증을 도입해서 로그인 → 토큰 발급 → 글 작성 요청 까지 연결하는 흐름을 만든다.
워드프레스 관리자 페이지에서 이 플러그인을 설치한다: 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을 열었을 때, 토큰이 없다면 바로 login.html로 보내버린다.HTML로 웹을 구현한다면 매 페이지 이 동작이 필요하다.
const token = localStorage.getItem('jwt_token'); if (!token) { window.location.href = 'login.html'; }
다시한번 정리하는 목표로 하고있는 index.html 구조를 요약해본다.
글 작성을 위한 별도 페이지는 없다.트위터같은 느낌의 메인 화면에서 모든 걸 처리한다.
글 작성 영역(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('게시 실패! 로그인 상태를 확인하세요.'); } }
예시: 예약발행
{ "title": "예약된 글", "content": "이 글은 나중에 자동으로 공개됩니다.", "status": "future", "date": "2025-04-10T10:00:00" }
필요에 따라 버튼 UI를 다르게 구성하여 "임시 저장" 버튼 누르면 "status": "draft"로 보내고, "발행하기" 버튼 누르면 "publish"로 보내는 식으로 게시물을 작성할 수 있지만 지금 내가 만들려고하는 사이트에서는 이런 기능이 필요 없기에 사용하지는 않을 예정.