feat: enhance party user authentication endpoint with improved error handling, logging, and PartyUser model integration

This commit is contained in:
louiscklaw
2025-06-18 10:52:00 +08:00
parent 8bb6c9e992
commit 779984f65c
3 changed files with 51 additions and 26 deletions

View File

@@ -1,5 +1,14 @@
import type { User } from '@prisma/client';
// src/app/api/party-user-auth/me/route.ts
//
// PURPOSE:
// - Handle authentication for party users via JWT
// - Verify and decode JWT tokens
// - Return current authenticated party user details
// - Log all access attempts (success/failure)
// - Validate token structure and user existence
//
import type { NextRequest } from 'next/server';
import type { PartyUser } from '@prisma/client';
import { headers } from 'next/headers';
@@ -7,15 +16,13 @@ import { verify } from 'src/utils/jwt';
import { STATUS, response, handleError } from 'src/utils/response';
import { JWT_SECRET } from 'src/_mock/_auth';
import { getUserById } from 'src/app/services/user.service';
import { createAccessLog } from 'src/app/services/access-log.service';
import { getPartyUserById } from 'src/app/services/party-user.service';
import { flattenNextjsRequest } from '../sign-in/flattenNextjsRequest';
// ----------------------------------------------------------------------
// export const runtime = 'edge';
/**
* This API is used for demo purpose only
* You should use a real database
@@ -24,11 +31,12 @@ import { flattenNextjsRequest } from '../sign-in/flattenNextjsRequest';
* You should not expose the JWT_SECRET in the client side
*/
const USER_TOKEN_CHECK_FAILED = 'user token check failed';
const INVALID_AUTH_TOKEN = 'Invalid authorization token';
const USER_ID_NOT_FOUND = 'userId not found';
const ERR_USER_TOKEN_CHECK_FAILED = 'user token check failed';
const ERR_INVALID_AUTH_TOKEN = 'Invalid authorization token';
const ERR_USER_ID_NOT_FOUND = 'userId not found';
const ERR_AUTHORIZATION_TOKEN_MISSING_OR_INVALID = 'Authorization token missing or invalid';
const USER_TOKEN_OK = 'user token check ok';
const AUTHORIZATION_TOKEN_MISSING_OR_INVALID = 'Authorization token missing or invalid';
export async function GET(req: NextRequest) {
const debug = { 'req.headers': flattenNextjsRequest(req) };
@@ -38,29 +46,29 @@ export async function GET(req: NextRequest) {
const authorization = headersList.get('authorization');
if (!authorization || !authorization.startsWith('Bearer ')) {
return response({ message: AUTHORIZATION_TOKEN_MISSING_OR_INVALID }, STATUS.UNAUTHORIZED);
return response({ message: ERR_AUTHORIZATION_TOKEN_MISSING_OR_INVALID }, STATUS.UNAUTHORIZED);
}
const accessToken = `${authorization}`.split(' ')[1];
const data = await verify(accessToken, JWT_SECRET);
console.log(data.userId);
if (data.userId) {
// TODO: remove me
// const currentUser = _users.find((user) => user.id === data.userId);
const currentUser: User | null = await getUserById(data.userId);
// const currentUser: User | null = await getUserById(data.userId);
const currentUser: PartyUser | null = await getPartyUserById(data.userId);
if (!currentUser) {
createAccessLog('', USER_TOKEN_CHECK_FAILED, debug);
createAccessLog('', ERR_USER_TOKEN_CHECK_FAILED, debug);
return response({ message: INVALID_AUTH_TOKEN }, STATUS.UNAUTHORIZED);
return response({ message: ERR_INVALID_AUTH_TOKEN }, STATUS.UNAUTHORIZED);
}
createAccessLog(currentUser.id, USER_TOKEN_OK, debug);
return response({ user: currentUser }, STATUS.OK);
} else {
return response({ message: USER_ID_NOT_FOUND }, STATUS.ERROR);
return response({ message: ERR_USER_ID_NOT_FOUND }, STATUS.ERROR);
}
} catch (error) {
return handleError('[Auth] - Me', error);

View File

@@ -1,22 +1,35 @@
// Test cases for Party User Authentication endpoints
// Tests both successful and error scenarios
// Environment: http://localhost:7272
// Expected responses:
// - 200 OK with user data for valid tokens
// - 401 Unauthorized for invalid/missing tokens
// - 400 Bad Request for invalid credentials
###
# username and password ok
GET http://localhost:7272/api/auth/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjbWJnbnUyengwMDBjaHEzaGZ3dmtjejlvIiwiaWF0IjoxNzQ4OTY0ODkyLCJleHAiOjE3NTAxNzQ0OTJ9.lo04laCxtm0IVeYaETEV3hXKyDmXPEn7SyWtY2VR4dI
GET http://localhost:7272/api/party-user-auth/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjbWMwdWo4azIwMDBxM2Y1eTZlNXJzejRxIiwiaWF0IjoxNzUwMjEzOTkwLCJleHAiOjE3NTE0MjM1OTB9.MoKv3Nmrp_blE0jQ1rG1WyQ_TrJeF7kSe5xfHrF8b64
###
# There is no user corresponding to the email address.
POST http://localhost:7272/api/auth/sign-in
POST http://localhost:7272/api/party-user-auth/sign-in
content-type: application/json
{
"email": "demo@minimals1.cc",
"email": "demo@minimals.cc",
"password": "@2Minimal"
}
###
# Wrong password
POST http://localhost:7272/api/auth/sign-in
POST http://localhost:7272/api/party-user-auth/sign-in
content-type: application/json
{

View File

@@ -1,14 +1,18 @@
// src/app/services/user.service.ts
// src/app/services/party-user.service.ts
//
// PURPOSE:
// - Handle User Record CRUD operations
// - Handle Party User Record CRUD operations
// - Manage party member data and permissions
// - Interface between controllers and database
//
// RULES:
// - Follow Prisma best practices for database operations
// - Validate input data before processing
// - Validate all party user data before processing
// - Enforce party-specific business rules
// - Maintain audit trail for sensitive operations
//
import type { User, PartyUser } from '@prisma/client';
import type { PartyUser } from '@prisma/client';
import prisma from '../lib/prisma';
@@ -47,8 +51,8 @@ async function getPartyUserByEmail(email: string): Promise<PartyUser | null> {
});
}
async function getUserById(id: string): Promise<User | null> {
return prisma.user.findFirst({ where: { id } });
async function getPartyUserById(id: string): Promise<PartyUser | null> {
return prisma.partyUser.findFirst({ where: { id } });
}
async function createPartyUser(partyUserData: any): Promise<PartyUser> {
@@ -69,7 +73,7 @@ async function deletePartyUser(partyUserId: string): Promise<PartyUser | null> {
}
export {
getUserById,
getPartyUserById,
getPartyUser,
listPartyUsers,
createPartyUser,