Menus.cs 23 KB

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