Menus.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. using Microsoft.AspNetCore.Authorization;
  2. using System.Security.Claims;
  3. namespace Admin.Constants
  4. {
  5. public class Menu
  6. {
  7. public int Id { get; set; }
  8. public required string Name { get; set; }
  9. public string? Path { get; set; }
  10. public string? Icon { get; set; }
  11. public List<Menu>? Children { get; set; } = [];
  12. public bool HasChildren => Children != null && Children.Count > 0;
  13. // 이 메뉴를 볼 수 있는 역할 목록 (없으면 모두 허용)
  14. public List<string>? Roles { get; set; }
  15. // 정책 이름으로도 제한 가능하게
  16. public List<string>? Policies { get; set; }
  17. }
  18. public static class Menus
  19. {
  20. public static List<Menu> GetMenus()
  21. {
  22. return new List<Menu>
  23. {
  24. new Menu
  25. {
  26. Id = 100,
  27. Name = "상황판",
  28. Path = "/",
  29. Icon = "<i class=\"bi bi-speedometer\"></i>",
  30. Children = null,
  31. Roles = new List<string> { "Admin", "상황판" },
  32. Policies = null
  33. },
  34. new Menu
  35. {
  36. Id = 200,
  37. Name = "환경",
  38. Path = null,
  39. Icon = "<i class=\"bi bi-gear\"></i>",
  40. Roles = new List<string> { "Admin", "환경" },
  41. Children = new List<Menu>
  42. {
  43. new Menu
  44. {
  45. Id = 201,
  46. Name = "서버 정보",
  47. Path = "/Systems/Server",
  48. Roles = new List<string> { "Admin", "환경 - 서버 정보" },
  49. Policies = null
  50. },
  51. new Menu
  52. {
  53. Id = 202,
  54. Name = "환경변수",
  55. Path = "/Systems/Envs",
  56. Roles = new List<string> { "Admin", "환경 - 환경변수" }
  57. },
  58. new Menu
  59. {
  60. Id = 203,
  61. Name = "기본 설정",
  62. Path = "/Systems/Basic",
  63. Roles = new List<string> { "Admin", "환경 - 기본 설정" }
  64. },
  65. new Menu
  66. {
  67. Id = 204,
  68. Name = "메타 태그",
  69. Path = "/Systems/Meta",
  70. Roles = new List<string> { "Admin", "환경 - 메타 태그" }
  71. },
  72. new Menu
  73. {
  74. Id = 205,
  75. Name = "회사 정보",
  76. Path = "/Systems/Company",
  77. Roles = new List<string> { "Admin", "환경 - 회사 정보" }
  78. },
  79. new Menu
  80. {
  81. Id = 207,
  82. Name = "회원 설정",
  83. Path = "/Systems/Register",
  84. Roles = new List<string> { "Admin", "환경 - 회원 설정" }
  85. },
  86. new Menu
  87. {
  88. Id = 208,
  89. Name = "알림 발송 확인",
  90. Path = "/Systems/Test",
  91. Roles = new List<string> { "Admin", "환경 - 알림 발송 확인" }
  92. },
  93. new Menu
  94. {
  95. Id = 209,
  96. Name = "알림 발송 양식",
  97. Path = "/Systems/Template/Email",
  98. Roles = new List<string> { "Admin", "환경 - 알림 발송 양식" }
  99. },
  100. new Menu
  101. {
  102. Id = 211,
  103. Name = "API 설정",
  104. Path = "/Systems/External",
  105. Roles = new List<string> { "Admin", "환경 - API 설정" }
  106. },
  107. new Menu
  108. {
  109. Id = 212,
  110. Name = "결제 설정",
  111. Path = "/Systems/Payment",
  112. Roles = new List<string> { "Admin", "환경 - 결제 설정" }
  113. },
  114. new Menu
  115. {
  116. Id = 213,
  117. Name = "관리자",
  118. Path = "/Director/User",
  119. Roles = new List<string> { "Admin", "환경 - 관리자" }
  120. }
  121. }
  122. },
  123. new Menu
  124. {
  125. Id = 300,
  126. Name = "일반",
  127. Path = null,
  128. Icon = "<i class=\"bi bi-card-heading\"></i>",
  129. Roles = new List<string> { "Admin", "일반" },
  130. Children = new List<Menu>
  131. {
  132. new Menu
  133. {
  134. Id = 301,
  135. Name = "문서 관리",
  136. Path = "/Page/Document",
  137. Roles = new List<string> { "Admin", "일반 - 문서 관리" }
  138. },
  139. new Menu
  140. {
  141. Id = 302,
  142. Name = "FAQ 관리",
  143. Path = "/Page/Faq/Item",
  144. Roles = new List<string> { "Admin", "일반 - FAQ 관리" },
  145. Children = new List<Menu>
  146. {
  147. new Menu
  148. {
  149. Id = 3021,
  150. Name = "FAQ 분류",
  151. Path = "/Page/Faq/Category",
  152. Roles = new List<string> { "Admin", "일반 - FAQ 분류" }
  153. },
  154. new Menu
  155. {
  156. Id = 3022,
  157. Name = "FAQ 항목",
  158. Path = "/Page/Faq/Item",
  159. Roles = new List<string> { "Admin", "일반 - FAQ 항목" }
  160. }
  161. }
  162. },
  163. new Menu
  164. {
  165. Id = 303,
  166. Name = "팝업 관리",
  167. Path = "/Page/Popup",
  168. Roles = new List<string> { "Admin", "일반 - 팝업 관리" }
  169. },
  170. new Menu
  171. {
  172. Id = 304,
  173. Name = "배너 관리",
  174. Roles = new List<string> { "Admin", "일반 - 배너 관리" },
  175. Children = new List<Menu>
  176. {
  177. new Menu
  178. {
  179. Id = 3041,
  180. Name = "배너 위치",
  181. Path = "/Page/Banner/Position",
  182. Roles = new List<string> { "Admin", "일반 - 배너 위치" }
  183. },
  184. new Menu
  185. {
  186. Id = 3042,
  187. Name = "배너 관리",
  188. Path = "/Page/Banner/Item",
  189. Roles = new List<string> { "Admin", "일반 - 배너 관리" }
  190. }
  191. }
  192. }
  193. }
  194. },
  195. new Menu
  196. {
  197. Id = 400,
  198. Name = "회원",
  199. Path = null,
  200. Icon = "<i class=\"bi bi-people\"></i>",
  201. Roles = new List<string> { "Admin", "회원" },
  202. Children = new List<Menu>
  203. {
  204. new Menu
  205. {
  206. Id = 401,
  207. Name = "회원 목록",
  208. Path = "/Member/List",
  209. Roles = new List<string> { "Admin", "회원 - 회원 목록" }
  210. },
  211. new Menu
  212. {
  213. Id = 402,
  214. Name = "회원 등급",
  215. Path = "/Member/Grade",
  216. Roles = new List<string> { "Admin", "회원 - 회원 등급" }
  217. },
  218. new Menu
  219. {
  220. Id = 403,
  221. Name = "현재 접속자",
  222. Path = "/Member/Visitor",
  223. Roles = new List<string> { "Admin", "회원 - 현재 접속자" }
  224. },
  225. new Menu
  226. {
  227. Id = 404,
  228. Name = "로그인 내역",
  229. Path = "/Member/Log/Login",
  230. Roles = new List<string> { "Admin", "회원 - 로그인 내역" }
  231. },
  232. new Menu
  233. {
  234. Id = 405,
  235. Name = "이메일 변경 내역",
  236. Path = "/Member/Log/Email",
  237. Roles = new List<string> { "Admin", "회원 - 이메일 변경 내역" }
  238. },
  239. new Menu
  240. {
  241. Id = 406,
  242. Name = "별명 변경 내역",
  243. Path = "/Member/Log/Name",
  244. Roles = new List<string> { "Admin", "회원 - 별명 변경 내역" }
  245. },
  246. new Menu
  247. {
  248. Id = 407,
  249. Name = "한마디 변경 내역",
  250. Path = "/Member/Log/Summary",
  251. Roles = new List<string> { "Admin", "회원 - 한마디 변경 내역" }
  252. },
  253. new Menu
  254. {
  255. Id = 408,
  256. Name = "자기소개 변경 내역",
  257. Path = "/Member/Log/Intro",
  258. Roles = new List<string> { "Admin", "회원 - 자기소개 변경 내역" }
  259. },
  260. new Menu
  261. {
  262. Id = 409,
  263. Name = "지갑 관리",
  264. Path = "/Member/Wallet/List",
  265. Roles = new List<string> { "Admin", "회원 - 지갑 관리", "Joblepay" }
  266. },
  267. new Menu
  268. {
  269. Id = 410,
  270. Name = "거래 장부",
  271. Path = "/Member/Wallet/Transactions",
  272. Roles = new List<string> { "Admin", "회원 - 거래 장부" }
  273. }
  274. }
  275. },
  276. new Menu
  277. {
  278. Id = 500,
  279. Name = "게시판",
  280. Path = null,
  281. Icon = "<i class=\"bi bi-clipboard2\"></i>",
  282. Roles = new List<string> { "Admin", "게시판" },
  283. Children = new List<Menu>
  284. {
  285. new Menu
  286. {
  287. Id = 501,
  288. Name = "분류 관리",
  289. Path = "/Forum/Board/Group",
  290. Roles = new List<string> { "Admin", "게시판 - 분류 관리" }
  291. },
  292. new Menu
  293. {
  294. Id = 502,
  295. Name = "게시판 관리",
  296. Path = "/Forum/Board/List",
  297. Roles = new List<string> { "Admin", "게시판 - 게시판 관리" }
  298. },
  299. new Menu
  300. {
  301. Id = 503,
  302. Name = "게시물 관리",
  303. Path = "/Forum/Post/List",
  304. Roles = new List<string> { "Admin", "게시판 - 게시물 관리" }
  305. },
  306. new Menu
  307. {
  308. Id = 504,
  309. Name = "휴지통",
  310. Path = "/Forum/Post/Trash",
  311. Roles = new List<string> { "Admin", "게시판 - 휴지통" }
  312. },
  313. new Menu
  314. {
  315. Id = 505,
  316. Name = "첨부파일",
  317. Path = "/Forum/Post/File",
  318. Roles = new List<string> { "Admin", "게시판 - 첨부파일" }
  319. },
  320. new Menu
  321. {
  322. Id = 506,
  323. Name = "이미지",
  324. Path = "/Forum/Post/Image",
  325. Roles = new List<string> { "Admin", "게시판 - 이미지" }
  326. },
  327. new Menu
  328. {
  329. Id = 507,
  330. Name = "반응 관리",
  331. Path = "/Forum/Post/Feedback",
  332. Roles = new List<string> { "Admin", "게시판 - 반응 관리" }
  333. },
  334. new Menu
  335. {
  336. Id = 508,
  337. Name = "신고 관리",
  338. Path = "/Forum/Post/Blame",
  339. Roles = new List<string> { "Admin", "게시판 - 신고 관리" }
  340. }
  341. }
  342. },
  343. new Menu
  344. {
  345. Id = 600,
  346. Name = "댓글",
  347. Path = null,
  348. Icon = "<i class=\"bi bi-chat\"></i>",
  349. Roles = new List<string> { "Admin", "댓글" },
  350. Children = new List<Menu>
  351. {
  352. new Menu
  353. {
  354. Id = 601,
  355. Name = "댓글 관리",
  356. Path = "/Forum/Comment/List",
  357. Roles = new List<string> { "Admin", "댓글 - 댓글 관리" }
  358. },
  359. new Menu
  360. {
  361. Id = 602,
  362. Name = "휴지통",
  363. Path = "/Forum/Comment/Trash",
  364. Roles = new List<string> { "Admin", "댓글 - 휴지통" }
  365. },
  366. new Menu
  367. {
  368. Id = 603,
  369. Name = "첨부파일",
  370. Path = "/Forum/Comment/File",
  371. Roles = new List<string> { "Admin", "댓글 - 첨부파일" }
  372. },
  373. new Menu
  374. {
  375. Id = 604,
  376. Name = "이미지",
  377. Path = "/Forum/Comment/Image",
  378. Roles = new List<string> { "Admin", "댓글 - 이미지" }
  379. },
  380. new Menu
  381. {
  382. Id = 605,
  383. Name = "공감 관리",
  384. Path = "/Forum/Comment/Feedback",
  385. Roles = new List<string> { "Admin", "댓글 - 공감 관리" }
  386. },
  387. new Menu
  388. {
  389. Id = 606,
  390. Name = "신고 관리",
  391. Path = "/Forum/Comment/Blame",
  392. Roles = new List<string> { "Admin", "댓글 - 신고 관리" }
  393. }
  394. }
  395. },
  396. new Menu
  397. {
  398. Id = 700,
  399. Name = "채널",
  400. Path = "/Channel/List",
  401. Icon = "<i class=\"bi bi-person-lines-fill\"></i>",
  402. Children = null,
  403. Roles = new List<string> { "Admin", "채널", "채널 - 채널 목록" }
  404. },
  405. new Menu
  406. {
  407. Id = 800,
  408. Name = "결제",
  409. Path = null,
  410. Icon = "<i class=\"bi bi-wallet2\"></i>",
  411. Roles = new List<string> { "Admin", "결제" },
  412. Children = new List<Menu>
  413. {
  414. new Menu
  415. {
  416. Id = 801,
  417. Name = "다날 결제 내역",
  418. Path = "/Payments/Danal/Confirm",
  419. Roles = new List<string> { "Admin", "결제 - 다날 결제 내역" }
  420. },
  421. new Menu
  422. {
  423. Id = 802,
  424. Name = "다날 취소 내역",
  425. Path = "/Payments/Danal/Cancel",
  426. Roles = new List<string> { "Admin", "결제 - 다날 취소 내역" }
  427. },
  428. new Menu
  429. {
  430. Id = 803,
  431. Name = "다날 오류 내역",
  432. Path = "/Payments/Danal/Error",
  433. Roles = new List<string> { "Admin", "결제 - 다날 오류 내역" }
  434. }
  435. }
  436. },
  437. new Menu
  438. {
  439. Id = 900,
  440. Name = "후원",
  441. Path = null,
  442. Icon = "<i class=\"bi bi-currency-exchange\"></i>",
  443. Roles = new List<string> { "Admin", "후원" },
  444. Children = new List<Menu>
  445. {
  446. new Menu
  447. {
  448. Id = 901,
  449. Name = "후원 내역",
  450. Path = "/Donation/List",
  451. Roles = new List<string> { "Admin", "후원 - 후원 내역" }
  452. },
  453. new Menu
  454. {
  455. Id = 902,
  456. Name = "후원 알림",
  457. Path = "/Donation/Alert",
  458. Roles = new List<string> { "Admin", "후원 - 후원 알림" }
  459. }
  460. }
  461. },
  462. new Menu
  463. {
  464. Id = 1000,
  465. Name = "정산",
  466. Path = null,
  467. Icon = "<i class=\"bi bi-piggy-bank\"></i>",
  468. Roles = new List<string> { "Admin", "정산" },
  469. Children = new List<Menu>
  470. {
  471. new Menu
  472. {
  473. Id = 1001,
  474. Name = "매출 관리",
  475. Path = "/Payout/Sales",
  476. Roles = new List<string> { "Admin", "정산 - 매출 관리" }
  477. },
  478. new Menu
  479. {
  480. Id = 1002,
  481. Name = "통계",
  482. Path = "/Payout/Statistics",
  483. Roles = new List<string> { "Admin", "정산 - 통계" }
  484. },
  485. new Menu
  486. {
  487. Id = 1003,
  488. Name = "회원 정산 내역",
  489. Path = "/Payout/Settlement/List",
  490. Roles = new List<string> { "Admin", "정산 - 회원 정산 내역" }
  491. }
  492. }
  493. }
  494. };
  495. }
  496. public static async Task<List<Menu>> FilterForUserAsync(ClaimsPrincipal user, IAuthorizationService authorizationService)
  497. {
  498. var menus = GetMenus();
  499. var result = new List<Menu>();
  500. foreach (var menu in menus)
  501. {
  502. var filtered = await FilterMenuRecursiveAsync(menu, user, authorizationService);
  503. if (filtered != null)
  504. {
  505. result.Add(filtered);
  506. }
  507. }
  508. return result;
  509. }
  510. private static async Task<Menu?> FilterMenuRecursiveAsync(Menu menu, ClaimsPrincipal user, IAuthorizationService authorizationService)
  511. {
  512. // 현재 메뉴에 대한 접근 권한 체크
  513. if (!await IsMenuAllowedAsync(menu, user, authorizationService))
  514. {
  515. // 자식이 있으면, 자식은 볼 수 있지만 부모는 숨기고 싶을 수도 있음
  516. if (menu.Children is { Count: > 0 })
  517. {
  518. var allowedChildren = new List<Menu>();
  519. foreach (var child in menu.Children)
  520. {
  521. var filteredChild = await FilterMenuRecursiveAsync(child, user, authorizationService);
  522. if (filteredChild != null)
  523. {
  524. allowedChildren.Add(filteredChild);
  525. }
  526. }
  527. if (allowedChildren.Count == 0)
  528. {
  529. return null;
  530. }
  531. return new Menu
  532. {
  533. Id = menu.Id,
  534. Name = menu.Name,
  535. Path = menu.Path,
  536. Icon = menu.Icon,
  537. Roles = menu.Roles,
  538. Policies = menu.Policies,
  539. Children = allowedChildren
  540. };
  541. }
  542. return null;
  543. }
  544. // 부모는 허용되지만, 자식 중 제한이 있을 수도 있으니
  545. List<Menu>? filteredChildren = null;
  546. if (menu.Children is { Count: > 0 })
  547. {
  548. filteredChildren = new List<Menu>();
  549. foreach (var child in menu.Children)
  550. {
  551. var filteredChild = await FilterMenuRecursiveAsync(child, user, authorizationService);
  552. if (filteredChild != null)
  553. {
  554. filteredChildren.Add(filteredChild);
  555. }
  556. }
  557. if (filteredChildren.Count == 0)
  558. {
  559. filteredChildren = null;
  560. }
  561. }
  562. return new Menu
  563. {
  564. Id = menu.Id,
  565. Name = menu.Name,
  566. Path = menu.Path,
  567. Icon = menu.Icon,
  568. Roles = menu.Roles,
  569. Policies = menu.Policies,
  570. Children = filteredChildren
  571. };
  572. }
  573. private static async Task<bool> IsMenuAllowedAsync(Menu menu, ClaimsPrincipal user, IAuthorizationService authorizationService)
  574. {
  575. // 로그인 안 한 경우: 익명에게도 보여줄 메뉴만 허용하고 싶으면 분기 추가
  576. if (!user.Identity?.IsAuthenticated ?? true)
  577. {
  578. // 예: 익명은 아무 메뉴도 못 본다고 가정
  579. return false;
  580. }
  581. // Roles 지정되어 있으면 Role 기반 체크
  582. if (menu.Roles is { Count: > 0 })
  583. {
  584. // 하나라도 만족하면 허용
  585. foreach (var role in menu.Roles)
  586. {
  587. if (user.IsInRole(role))
  588. {
  589. return true;
  590. }
  591. }
  592. return false;
  593. }
  594. // Policies 지정되어 있으면 Policy 기반 체크
  595. if (menu.Policies is { Count: > 0 })
  596. {
  597. foreach (var policy in menu.Policies)
  598. {
  599. var authResult = await authorizationService.AuthorizeAsync(user, policy);
  600. if (authResult.Succeeded)
  601. {
  602. return true;
  603. }
  604. }
  605. return false;
  606. }
  607. // 역할/정책 제한이 없으면 모두 허용
  608. return true;
  609. }
  610. }
  611. }