This commit is contained in:
bangdk 2024-11-23 07:59:18 +09:00
parent 379e7fb6c2
commit cc61bca776
7 changed files with 9450 additions and 10 deletions

View File

@ -5,6 +5,7 @@ const authService = require("../../../services/auth.service");
const { body } = require("express-validator");
const validate = require("../../../middleware/validator.middleware");
const authMiddleware = require("../../../middleware/auth.middleware");
const logger = require("../../../config/logger");
router.post(
"/login",
@ -60,4 +61,65 @@ router.post(
}
);
// 토큰 검증 엔드포인트
router.post("/validate", async (req, res, next) => {
try {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({
valid: false,
message: "Token is required",
});
}
const result = await authService.validateToken(token);
res.json(result);
} catch (error) {
logger.error("Validate endpoint error:", {
error: error.message,
stack: error.stack,
});
if (
error.name === "JsonWebTokenError" ||
error.name === "TokenExpiredError"
) {
return res.status(401).json({
valid: false,
message: error.message,
});
}
next(error);
}
});
// 토큰 갱신 엔드포인트
router.post("/refresh", async (req, res, next) => {
try {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({
message: "Token is required",
});
}
const result = await authService.refreshToken(token);
res.json(result);
} catch (error) {
logger.error("Refresh token endpoint error:", {
error: error.message,
stack: error.stack,
});
if (error.name === "JsonWebTokenError") {
return res.status(401).json({
message: "Invalid token",
});
}
next(error);
}
});
module.exports = router;

View File

@ -68,20 +68,11 @@ class AuthService {
const companyData = userData.Company || {};
delete userData.Roles;
// const userInfo = {
// ...userData,
// companyName: companyData.name,
// businessNumber: companyData.businessNumber,
// contractEndDate: companyData.contractEndDate,
// permissions,
// };
const userInfo = {
...userData,
companyId: companyData.id,
companyName: companyData.name,
businessNumber: companyData.businessNumber,
contractEndDate: companyData.contractEndDate,
branchId: userData.Branch?.id,
branchName: userData.Branch?.name,
permissions,
};
@ -205,12 +196,38 @@ class AuthService {
const userInfo = {
...userData,
companyName: companyData.name,
branchName: userData.Branch?.name,
businessNumber: companyData.businessNumber,
contractEndDate: companyData.contractEndDate,
permissions,
isEdgeLogin: true, // Edge 로그인 여부 표시
};
// const userInfo = {
// // 기본 사용자 정보
// id: userData.id,
// username: userData.username,
// name: userData.name,
// email: userData.email,
// phone: userData.phone,
// role: userData.role,
// isActive: userData.isActive,
// // 회사 정보
// companyId: companyData.id,
// companyName: companyData.name,
// businessNumber: companyData.businessNumber,
// contractEndDate: companyData.contractEndDate,
// // 지점 정보
// branchId: userData.Branch?.id,
// branchName: userData.Branch?.name,
// // 권한 및 기타 정보
// permissions,
// isEdgeLogin: true,
// };
const token = this._generateToken(userInfo);
return {
@ -333,6 +350,133 @@ class AuthService {
expiresIn: config.jwt.expiresIn,
});
}
async validateToken(token) {
try {
const decoded = jwt.verify(token, config.jwt.secret);
const user = await User.findOne({
where: { id: decoded.id },
include: [
{
model: Company,
attributes: ["id", "name", "businessNumber", "contractEndDate"],
where: { isActive: true },
},
{
model: Branch,
attributes: ["id", "name"],
},
{
model: Role,
through: { attributes: [] },
attributes: ["id", "name", "permissions"],
required: false,
},
],
attributes: {
exclude: ["password"],
},
});
if (!user || !user.isActive) {
throw new Error("User not found or inactive");
}
// 권한 정보 가공
const permissions = this._processPermissions(user.Roles || []);
// 사용자 정보 구성
const userData = user.toJSON();
const companyData = userData.Company || {};
delete userData.Roles;
const userInfo = {
...userData,
companyId: companyData.id,
companyName: companyData.name,
businessNumber: companyData.businessNumber,
contractEndDate: companyData.contractEndDate,
branchId: userData.Branch?.id,
branchName: userData.Branch?.name,
permissions,
};
return {
valid: true,
user: userInfo,
};
} catch (error) {
logger.error("Token validation error:", error.message);
throw error;
}
}
async refreshToken(token) {
try {
const decoded = jwt.verify(token, config.jwt.secret, {
ignoreExpiration: true,
});
const user = await User.findOne({
where: { id: decoded.id },
include: this._getUserIncludes(),
});
if (!user || !user.isActive) {
throw new Error("User not found or inactive");
}
const userInfo = this._formatUserInfo(user);
const newToken = this._generateToken(userInfo);
return {
token: newToken,
user: userInfo,
};
} catch (error) {
logger.error("Token refresh error:", error.message);
throw error;
}
}
_getUserIncludes() {
return [
{
model: Company,
attributes: ["id", "name", "businessNumber", "contractEndDate"],
where: { isActive: true },
},
{
model: Branch,
attributes: ["id", "name"],
},
{
model: Role,
through: { attributes: [] },
attributes: ["id", "name", "permissions"],
required: false,
},
];
}
_formatUserInfo(user) {
const userData = user.toJSON();
const companyData = userData.Company || {};
const permissions = this._processPermissions(userData.Roles || []);
delete userData.Roles;
return {
...userData,
companyId: companyData.id,
companyName: companyData.name,
businessNumber: companyData.businessNumber,
contractEndDate: companyData.contractEndDate,
branchId: userData.Branch?.id,
branchName: userData.Branch?.name,
permissions,
};
}
}
module.exports = new AuthService();

View File

@ -333,7 +333,7 @@ export function SideNav() {
<Building2 className="h-5 w-5 text-gray-500 mt-0.5" />
<div className="flex-1">
<h3 className="text-sm font-medium text-gray-900">
{user?.companyName}
{user?.companyName} - {user?.branchName}
</h3>
<p className="text-xs text-gray-500">
: {formatBusinessNumber(user?.businessNumber || "")}

View File

@ -20,6 +20,7 @@ export interface User {
businessNumber: string;
contractEndDate: string;
branchId?: string;
branchName: string;
permissions: Permissions; // 권한 정보 추가
}

View File

@ -13,6 +13,7 @@ export interface User {
businessNumber: string;
contractEndDate: string;
branchId?: string;
branchName: string;
departmentId?: string;
roleId?: string;
Company?: {

Binary file not shown.

File diff suppressed because it is too large Load Diff