[nextjs]SNS Server-29(myapp39)Β 

πŸ‘‰πŸ» νšŒμ›κ°€μž… 및 둜그인과 κ΄€λ ¨λœ κΈ°λŠ₯μž…λ‹ˆλ‹€.
These are features related to sign-up and login.

πŸ‘‰πŸ» myapp39μ—μ„œλŠ” 이전에 μ™„λ£Œλ˜μ§€ μ•Šμ•˜λ˜ 둜그인 κΈ°λŠ₯을 μ™„μ„±ν•©λ‹ˆλ‹€.
In myapp39, we complete the login functionality that was not finished previously.

πŸ‘‰πŸ» 전체 μ½”λ“œλŠ” κΉƒν—ˆλΈŒμ—μ„œ 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
You can find the full code on GitHub.

https://github.com/gideonslife01/flm-nextjs

πŸ“ 전체 ν”„λ‘œμ νŠΈ ꡬ쑰 / Overall Project Structure

myapp project/  
β”œβ”€β”€ app/  (Next.js App Router)
β”‚   β”œβ”€β”€ .well-known/webfinger/route.ts  -> webfinger
β”‚   β”œβ”€β”€ api/follow/route.ts    -> Follow API(temporary)
β”‚   β”œβ”€β”€ api/announce/route.ts  -> Boost(Announcement)
β”‚   β”œβ”€β”€ api/like/route.ts.     -> Like API
β”‚   β”œβ”€β”€ api/posts/route.ts     -> Writing API
β”‚   β”œβ”€β”€ api/timeline/route.ts  -> Timeline API
β”‚   β”œβ”€β”€ api/v1/instance/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/apps/route.ts.    -> auth
β”‚   β”œβ”€β”€ api/v1/accounts/verify_credentials/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/statuses/route.ts -> Write Post
β”‚   β”œβ”€β”€ api/v1/timelines/home/route.ts -> timeline
β”‚   β”œβ”€β”€ oauth/authorize/route.ts -> auth
β”‚   β”œβ”€β”€ oauth/token/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v2/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/followers/route.ts -> followers
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/following/route.ts -> following
β”‚   β”œβ”€β”€ api/auth/signup/route.ts  -> Signup
β”‚   β”œβ”€β”€ api/auth/login/route.ts   -> Login
β”‚   β”œβ”€β”€ api/auth/logout/route.ts  -> Logout
β”‚   β”œβ”€β”€ auth/signup/page.tsx -> Signup UI
β”‚   β”œβ”€β”€ auth/signup/page.tsx -> Login UI
β”‚   β”œβ”€β”€ users/[username]/
β”‚   β”‚   β”œβ”€β”€ statuses/[id]/route.ts -> Indivisual Post
β”‚   β”‚   β”œβ”€β”€ route.ts               -> Acotr Information
β”‚   β”‚   β”œβ”€β”€ followers/route.ts     -> Followers List
β”‚   β”‚   β”œβ”€β”€ following/route.ts     -> Following List
β”‚   β”‚   β”œβ”€β”€ inbox/route.ts         -> Inbox
β”‚   β”‚   └── outbox/route.ts        -> outbox
β”‚   β”œβ”€β”€ usersui/[username]/
β”‚   β”‚   β”œβ”€β”€ page.tsx               -> Timeline UI
β”‚   β”‚   └── _components/themes/
β”‚   β”‚       β”œβ”€β”€ themeex/ThemeexTheme.tsx   -> Example Theme
β”‚   β”‚       β”œβ”€β”€ pinafore/PinaforeTheme.tsx -> Theme 1
β”‚   β”‚       β”œβ”€β”€ mastodon/MastodonTheme.tsx -> Theme 2
β”‚   β”‚       └── minimal/MinimaltTheme.tsx  -> Theme 3
β”‚   β”œβ”€β”€ layout.tsx, page.tsx, globals.css
β”‚   └── favicon.ico
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ theme.tsx              -> Theme Provider
β”‚   β”œβ”€β”€ watchThemes.ts         -> Check real-time theme changes
β”‚   β”œβ”€β”€ auth.ts                -> Authentication, User Management
β”‚   β”œβ”€β”€ ap.ts                  -> Follow,Undo,Create,Likes,Announce
β”‚   └── db.ts                  -> DB connection
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ keys/userIDs/          -> private.pem, public.pem(New)
β”‚   └── keys/                  -> private.pem, public.pem(legacy)
β”œβ”€β”€ data.sqlite                -> Database(1/3)
β”œβ”€β”€ data.sqlite-wal            -> Database(2/3)
β”œβ”€β”€ data.sqlite-shm            -> Database(3/3)
β”œβ”€β”€ Caddyfile                  -> https 
β”œβ”€β”€ instrumentation.ts         -> Background Server
└── package.json

πŸ“ ν”„λ‘œμ νŠΈ μ‹œμž‘ / Project Start


πŸ“ 라우트 μΆ”κ°€ /. Add Route

βœ”οΈ app/api/auth/signup/route.ts – νšŒμ›κ°€μž… / Signup

βœ”οΈ app/api/auth/login/route.ts – 둜그인 / Login

βœ”οΈ app/auth/login/page.tsx – 둜그인 UI / Login UI

βœ”οΈ app/auth/signup/page.tsx – νšŒμ›κ°€μž… UI / Signup UI

βœ”οΈ app/api/auth/logout/route.ts – λ‘œκ·Έμ•„μ›ƒ / Logout

πŸ“ μ½”λ“œμˆ˜μ • / Code Modification

βœ”οΈ lib/auth.ts

export function getUsernameFromRequest(req: Request | NextRequest): string | null { ... }
export function getUsernameFromToken(token: string): string | null { ... }

βœ”οΈ app/api/v1/instance/route.ts

— OPTIONSν•¨μˆ˜ 제거(middleware.tsμ—μ„œ 처리)
Remove OPTIONS function (handled in middleware.ts)

// βœ… myapp39 - app/api/v1/instance/route.ts - middlewareκ°€! CORS 처리!ν•˜λ‹ˆκΉŒ! 깔끔!
import { NextResponse } from 'next/server';

const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';

export async function GET() {
  return NextResponse.json({
    uri: `https://${DOMAIN}`, 
    title: 'Aloy Horizon',
    short_description: 'My ActivityPub server!',
    description: 'My own Fediverse server running Next.js',
    email: 'admin@aloy-horizon.duckdns.org',
    version: '4.3.0 (compatible; Aloy Horizon 1.0)',
    urls: {
      streaming_api: `wss://${DOMAIN}`
    },
    stats: {
      user_count: 1,
      status_count: 100,
      domain_count: 1000
    },
    thumbnail: `https://${DOMAIN}/icon.png`,
    languages: ['en', 'ko'],
    registrations: true,
    approval_required: false,
    invites_enabled: false,
    configuration: {
      statuses: {
        max_characters: 500,
        max_media_attachments: 4
      }
    },
    rules: []
  });
}
// OPTIONSν•¨μˆ˜ 제거 middleware.tsμ—μ„œ 처리
// Remove OPTIONS function, handle in middleware.ts

βœ”οΈ app/oauth/authorize/route.ts – localhost:3000

... ...
const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';
//const DOMAIN = 'aloy-horizon.duckdns.org';
const ORIGIN = `https://${DOMAIN}`;
... ...
export async function GET(req: Request) { 
... ...
  // βœ… myapp39 - 둜그인 체크 / login check
  const username = getUsernameFromCookie(req);
... ...
 // βœ… for CORS error
  if (!username) {
      const loginUrl = new URL('/auth/login', ORIGIN); 
      const realNextUrl = `${ORIGIN}${url.pathname}${url.search}`;
      loginUrl.searchParams.set('next', realNextUrl);
      return NextResponse.redirect(loginUrl.toString());
  }
... ...
}

βœ”οΈ caddyfile

aloy-horizon.duckdns.org {
  reverse_proxy localhost:3000 {
    header_up Host {host}
    header_up X-Real-IP {remote}
    header_up X-Forwarded-For {remote}
    header_up X-Forwarded-Proto {scheme}
    header_up X-Forwarded-Host {host}
  }
 encode gzip
 
  # CORSλŠ”! Next.jsκ°€! 처리!ν•˜λ‹ˆκΉŒ! Caddyμ—μ„œ! 헀더! μΆ”κ°€! κΈˆμ§€!
  # Next.js handles CORS, so do not add headers in Caddy!
}

βœ”οΈ middleware.ts

— Pinaforeμ—μ„œ 둜그인 ν•˜λ©΄! ERR_CONNECTION_REFUSED + CORS
Logging in on Pinafore results in ERR_CONNECTION_REFUSED + CORS!

— λͺ¨λ“  μš”μ²­μ— CORS처리 적용 / Apply CORS handling to all requests.

// βœ… myapp39/middleware.ts - CORS 전체 처리 / Global CORS Handling
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(req: NextRequest) {

  // βœ… OPTIONS preflight λ¨Όμ € 처리
  // Process the OPTIONS preflight request first.
  if (req.method === 'OPTIONS') {
    return new NextResponse(null, {
      status: 204,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        'Access-Control-Max-Age': '86400',
      },
    });
  }

  // βœ… 일반 μš”μ²­ / General Request
  const res = NextResponse.next();
  res.headers.set('Access-Control-Allow-Origin', '*');
  res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  return res;
}

export const config = {
  matcher: ['/api/:path*', '/oauth/:path*', '/.well-known/:path*', '/users/:path*'],
};

πŸ“ ν…ŒμŠ€νŠΈ / Test

βœ”οΈ 터미널 ν…ŒμŠ€νŠΈ / Terminal test

# νšŒμ›κ°€μž… / Signup
curl -X POST https://aloy-horizon.duckdns.org/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"username":"test1","email":"test1@test.com","password":"123456","display_name":"Test1"}'

# Database
sqlite> select username from users;
test1
user1
user2
sqlite> 

βœ”οΈ μ›Ήμ‚¬μ΄νŠΈ 둜그인 / Website login

— https://aloy-horizon.duckdns.org/auth/login

1)pinaforeμ—μ„œ 둜그인 ν• κ²½μš°
When logging in on Pinafore

pinafore login

2)μ›Ήμ‚¬μ΄νŠΈμ—μ„œ 둜그인 ν• κ²½μš°
When logging in on the website

website login

βœ”οΈ λ‘œκ·Έμ•„μ›ƒ / Logout

Logout

βœ”οΈ μ›Ή νšŒμ›κ°€μž… / Website Signup

— https://aloy-horizon.duckdns.org/auth/signup

μš”ν•œλ³΅μŒ 8μž₯ 32절 / John 8:32

“그리고 λ„ˆν¬λŠ” 진리λ₯Ό μ•Œκ²Œ 될 것이며, 진리가 λ„ˆν¬λ₯Ό 자유둭게 ν•  것이닀.”

“Then you will know the truth ,and the truth will set you free”

Leave a Reply