Menus.cs 27 KB

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