0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】ログアウト等画面遷移の実装方法 | ポートフォリオ開発記録#6

0
Posted at

まえがき

本文

この記事の対象者

ここも第1回とほぼ同じですね。
要するに、完全未経験を除いた初心者です。

前提

以下インストール済(インストール方法は省略)
・React 19.0.0
・Next.js 16.0.0
・App Router
・Java 21
・Spring Boot 4.1
・jjwt-api 0.12.5

1.サイドバー

import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useAuth } from '../context/AuthContext'

function Sidebar() {

  const router = useRouter()
  const { logout } = useAuth()

  const handleLogout = async () => {
    if (confirm("ログアウトしますか?")) {
      await logout()
      router.push("/")
    }
  }

  return (
    <nav>
      <ul>
        <li>
          <Link href="/home">
            ホーム
          </Link>
        </li>

        (上記と同じものがいくつか続く)

      </ul>

      <button
        onClick={handleLogout}
      >
        ログアウト
      </button>

    </nav>
  )
}

export default Sidebar

2.ログイン後画面共通のlayout.tsx

import Sidebar from "../../components/Sidebar";

  return (
    <div>
      <div>
        <Sidebar />
      </div>

      <div>
        {children}
      </div>
    </div>
  );

3.useAuthの共通部品

以下のように追記します。

type AuthContextType = {
  isLoggedIn: boolean;
  isLoading: boolean;
  login: () => Promise<void>;
  logout: () => void;
  checkAuth: () => Promise<void>;
};
  // ログアウト時は未ログイン状態に戻す
const logout = async () => {

  try {
    await fetch("/api/auth/logout", {
      method: "POST",
      credentials: "include",
    });
  } finally {
    setIsLoggedIn(false);
  }
};

4.API部品

route.ts
import { NextResponse } from "next/server";

export async function POST(request: Request) {

  const springResponse = await fetch(
    `${process.env.SPRING_BOOT_API_BASE_URL}/api/auth/logout`,
    {
      method: "POST",
      headers: {
        Cookie: request.headers.get("cookie") ?? "",
      },
    }
  );

  const response = new NextResponse(null, {
    status: springResponse.status,
  });

  springResponse.headers.getSetCookie().forEach((cookie) => {
    response.headers.append("set-cookie", cookie);
  });

  return response;
}

5.Controller

以下のように追記。

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    // ログアウトしてJWT Cookieを削除する
    @PostMapping ("/logout")
    public ResponseEntity<?> logout(Authentication authentication) {

        // accessTokenを削除するCookieを返す ※LoginControllerとほぼ同じ構成
        ResponseCookie cookie = ResponseCookie.from("accessToken", "")
                .httpOnly(true)
                .secure(false)
                .sameSite("Lax")
                .path("/")
                .maxAge(Duration.ZERO)
                .build();

        // 削除用のCookieをブラウザに返す
        return ResponseEntity.ok()
                .header(HttpHeaders.SET_COOKIE, cookie.toString())
                .build();
    }
}

あとがき

上記によりログアウトボタンを実装したサイドバーが作れました。
これでCookieを用いた認証情報も削除しているので、ログアウトした後でリンク直打ちしても入れないです。
サイドバーを実装する機会がなくともログアウトボタンとリンクオブジェクトを実装する必要はあるでしょうし、オブジェクトの種類が違っていても本体はOnClick属性による関数の呼び出しなので流用可能。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?