Files
egret-app-template/packages/server/src/middleware/auth.ts

179 lines
4.5 KiB
TypeScript
Raw Normal View History

import {Request, Response, NextFunction} from "express";
import axios from "axios";
export type UserInfo = {
userId: number;
nickname: string;
avatarUrl: string;
gender: 'MALE' | 'FEMALE' | 'UNKNOWN';
nimToken: string; // NetEase Cloud Communication token
nimAccountId: string; // NetEase Cloud Communication account ID
createdAt: string;
updatedAt: string;
}
declare global {
namespace Express {
interface Request {
userInfo?: UserInfo | null;
groupInfo?: {
groupId: number;
users: UserInfo[];
} | null;
}
}
}
/**
* Extract Bearer token from request header
*/
export const extractTokenFromHeader = (authHeader: string | undefined): string | null => {
if (!authHeader) {
return null;
}
const parts = authHeader.split(" ");
if (parts.length !== 2 || parts[0] !== "Bearer") {
return null;
}
return parts[1];
};
/**
* Get user information by token
*/
export const getUserInfoByToken = async (token: string): Promise<any> => {
try {
const response = await axios.post(
"https://egret.byteawake.com/api/user/info",
{}, // 请求体数据,这里为空对象
{
headers: {
Authorization: `Bearer ${token}`,
},
timeout: 10000, // 10 second timeout
}
);
return response.data;
} catch (error: any) {
if (error.response) {
// API returned error response
throw new Error(`Failed to get user information: ${error.response.status} ${error.response.statusText}`);
} else if (error.request) {
// Request was sent but no response received
throw new Error("Failed to get user information: timeout or network error");
} else {
// Other errors
throw new Error(`Failed to get user information: ${error.message}`);
}
}
};
/**
* User information middleware
* Automatically extract token from request header and get user information, store result in req.userInfo
*/
export const userInfoMiddleware = async (
req: Request,
res: Response,
next: NextFunction
): Promise<void> => {
try {
const authHeader = req.headers.authorization;
const token = extractTokenFromHeader(authHeader);
if (!token) {
res.status(401).json({
error: "No valid access token provided",
message: "Missing Bearer token in Authorization header",
});
return;
}
// Get user information
const userInfoRes = await getUserInfoByToken(token);
req.userInfo = userInfoRes.code === 200 ? userInfoRes.data : null;
next();
} catch (error: any) {
res.status(401).json({
error: "User authentication failed",
message: error.message,
});
}
};
//////// group
/**
* Get group users
*/
export const getGroupUsers = async (groupId: number, token: string): Promise<any> => {
try {
const response = await axios.post<UserInfo[]>(
"https://egret.byteawake.com/api/group/members",
{groupId},
{
headers: {
Authorization: `Bearer ${token}`,
},
timeout: 10000, // 10 second timeout
}
);
return response.data;
} catch (error: any) {
if (error.response) {
// API returned error response
throw new Error(`Failed to get user information: ${error.response.status} ${error.response.statusText}`);
} else if (error.request) {
// Request was sent but no response received
throw new Error("Failed to get user information: timeout or network error");
} else {
// Other errors
throw new Error(`Failed to get user information: ${error.message}`);
}
}
};
/**
* group information middleware
*/
export const groupInfoMiddleware = async (
req: Request,
res: Response,
next: NextFunction
): Promise<void> => {
try {
const authHeader = req.headers.authorization;
const token = extractTokenFromHeader(authHeader);
const groupId = req.headers.groupid;
if (token && groupId) {
try {
const usersRes = await getGroupUsers(Number(groupId), token);
const users: UserInfo[] = usersRes.code === 200 ? usersRes.data : [];
req.groupInfo = {
groupId: Number(groupId),
users,
}
} catch (error) {
// If getting user information fails, do not block the request from continuing, but do not set userInfo
console.warn("Failed to get group user information:", error);
}
}
next();
} catch (error: any) {
res.status(400).json({
error: "Get Group Users failed",
message: error.message,
});
}
};