diff --git a/src/main/java/org/casbin/Application.java b/src/main/java/org/casbin/Application.java index c8137f6..9abdd52 100644 --- a/src/main/java/org/casbin/Application.java +++ b/src/main/java/org/casbin/Application.java @@ -14,14 +14,37 @@ package org.casbin; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; @SpringBootApplication +@Slf4j public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); + public static void main(String[] args) throws UnknownHostException { + ConfigurableApplicationContext application = SpringApplication.run(Application.class, args); + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path"); + if (StringUtils.isEmpty(path)) { + path = ""; + } + log.info("\n----------------------------------------------------------\n\t" + + "Application is running! Access URLs:\n\t" + + "Local access website: \t\thttp://localhost:" + port + path + "\n\t" + + "External access website: \thttp://" + ip + ":" + port + path + "\n\t" + + "----------------------------------------------------------"); + String jvmName = ManagementFactory.getRuntimeMXBean().getName(); + log.info("Current project progress number:" + jvmName.split("@")[0]); } } + diff --git a/src/main/java/org/casbin/controller/LoginController.java b/src/main/java/org/casbin/controller/LoginController.java index ebad95a..4fb311e 100644 --- a/src/main/java/org/casbin/controller/LoginController.java +++ b/src/main/java/org/casbin/controller/LoginController.java @@ -16,43 +16,29 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import org.casbin.service.AuthenticationService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller public class LoginController { - @Autowired - private AuthenticationService authenticationService; - @RequestMapping(value = {"/"}, method = RequestMethod.GET) public String index() { return "main/login"; } @RequestMapping(value = "/login", method = RequestMethod.POST) - public String login(@RequestParam String username, @RequestParam String password, HttpSession session, HttpServletRequest request, RedirectAttributes redirectAttributes) { - boolean isAuthenticated = authenticationService.authenticate(username, password); - - if (isAuthenticated) { - session.invalidate(); - session = request.getSession(true); - session.setAttribute("username", username); - return "redirect:/menu"; - } else { - redirectAttributes.addAttribute("error", true); - return "redirect:/login"; - } + public String login(@RequestParam String username, HttpSession session, HttpServletRequest request) { + session.invalidate(); + session = request.getSession(true); + session.setAttribute("username", username); + return "redirect:/menu"; } @RequestMapping(value = {"/denied"}, method = RequestMethod.GET) public String denied() { return "main/denied"; } -} - +} \ No newline at end of file diff --git a/src/main/java/org/casbin/service/AuthenticationService.java b/src/main/java/org/casbin/service/AuthenticationService.java deleted file mode 100644 index aa16180..0000000 --- a/src/main/java/org/casbin/service/AuthenticationService.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024 The casbin Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package org.casbin.service; - -import org.springframework.stereotype.Service; - -@Service -public class AuthenticationService { - public boolean authenticate(String username, String password) { - // Three valid username and password combinations are set here. - return ("root".equals(username) && "root".equals(password)) || - ("admin".equals(username) && "admin".equals(password)) || - ("user".equals(username) && "user".equals(password)); - } -} - - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 84f0921..75fa716 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -37,6 +37,4 @@ spring: max-file-size: 2048MB server: - port: 8080 - servlet: - context-path: /casbin \ No newline at end of file + port: 8080 \ No newline at end of file diff --git a/src/main/resources/templates/AdminMenu/AdminMenu.html b/src/main/resources/templates/AdminMenu/AdminMenu.html index c986868..2abe406 100644 --- a/src/main/resources/templates/AdminMenu/AdminMenu.html +++ b/src/main/resources/templates/AdminMenu/AdminMenu.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>AdminMenu</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/AdminMenu/AdminSubMenu_allow.html b/src/main/resources/templates/AdminMenu/AdminSubMenu_allow.html index cd91397..8cd0e85 100644 --- a/src/main/resources/templates/AdminMenu/AdminSubMenu_allow.html +++ b/src/main/resources/templates/AdminMenu/AdminSubMenu_allow.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>AdminSubMenu_allow</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/AdminMenu/AdminSubMenu_deny.html b/src/main/resources/templates/AdminMenu/AdminSubMenu_deny.html index fb72b5a..96fec8a 100644 --- a/src/main/resources/templates/AdminMenu/AdminSubMenu_deny.html +++ b/src/main/resources/templates/AdminMenu/AdminSubMenu_deny.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>AdminSubMenu_deny</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/OtherMenu/OtherMenu.html b/src/main/resources/templates/OtherMenu/OtherMenu.html index cddee05..2e1e270 100644 --- a/src/main/resources/templates/OtherMenu/OtherMenu.html +++ b/src/main/resources/templates/OtherMenu/OtherMenu.html @@ -2,12 +2,23 @@ <html lang="en"> <head> <meta charset="UTF-8"> - <title>SystemMenu</title> + <title>OtherMenu</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> OtherMenu </div> - </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/UserMenu/UserMenu.html b/src/main/resources/templates/UserMenu/UserMenu.html index f06186b..4d51739 100644 --- a/src/main/resources/templates/UserMenu/UserMenu.html +++ b/src/main/resources/templates/UserMenu/UserMenu.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>UserMenu</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/UserMenu/UserSubMenu_allow.html b/src/main/resources/templates/UserMenu/UserSubMenu_allow.html index 0f4881e..8673458 100644 --- a/src/main/resources/templates/UserMenu/UserSubMenu_allow.html +++ b/src/main/resources/templates/UserMenu/UserSubMenu_allow.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>UserSubMenu_allow</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/UserMenu/UserSubMenu_deny.html b/src/main/resources/templates/UserMenu/UserSubMenu_deny.html index 4338eea..75e2307 100644 --- a/src/main/resources/templates/UserMenu/UserSubMenu_deny.html +++ b/src/main/resources/templates/UserMenu/UserSubMenu_deny.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>UserSubMenu_deny</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/UserMenu/UserSubSubMenu.html b/src/main/resources/templates/UserMenu/UserSubSubMenu.html index 1b580eb..a357474 100644 --- a/src/main/resources/templates/UserMenu/UserSubSubMenu.html +++ b/src/main/resources/templates/UserMenu/UserSubSubMenu.html @@ -3,6 +3,18 @@ <head> <meta charset="UTF-8"> <title>UserSubSubMenu</title> + <style> + body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + } + div { + font-size: 24px; + } + </style> </head> <body> <div> diff --git a/src/main/resources/templates/main/login.html b/src/main/resources/templates/main/login.html index 2fc9010..7dd71cd 100644 --- a/src/main/resources/templates/main/login.html +++ b/src/main/resources/templates/main/login.html @@ -2,26 +2,22 @@ <html lang="en"> <head> <meta charset="UTF-8"> - <title>login</title> + <title>Login</title> + <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> </head> -<body> -<div class="panel panel-primary" style="width: 500px; margin: 5% auto;"> - <div class="panel-heading">login</div> - <div class="panel-body"> - <form action="login" method="post" class="form-horizontal"> - <div class="input-group input-sm" style="margin-bottom: 10px"> - <label class="input-group-addon"><i class="glyphicon glyphicon-user"></i></label> - <input type="text" class="form-control" name="username" placeholder="username"> - </div> - <div class="input-group input-sm" style="margin-bottom: 10px"> - <label class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></label> - <input type="password" class="form-control" name="password" placeholder="password"> - </div> - <div class="form-actions"> - <input type="submit" class="btn btn-block btn-primary btn-default" value="sign in"> - </div> +<body class="flex h-screen bg-gray-200"> +<div class="m-auto w-full max-w-xs"> + <div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"> + <div class="mb-4"> + <h1 class="block text-gray-700 text-sm font-bold mb-2">Login as:</h1> + </div> + <form action="login" method="post"> + <input type="hidden" name="password" value="dummy"> + <button type="submit" name="username" value="root" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline mb-3 w-full">Root</button> + <button type="submit" name="username" value="admin" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline mb-3 w-full">Admin</button> + <button type="submit" name="username" value="user" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline w-full">User</button> </form> </div> </div> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/main/menu.html b/src/main/resources/templates/main/menu.html index 960f8b6..caa1bec 100644 --- a/src/main/resources/templates/main/menu.html +++ b/src/main/resources/templates/main/menu.html @@ -1,108 +1,94 @@ <!DOCTYPE html> -<html lang="en"> +<html lang="en" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> - <title>Jcasbin-Menu-Permission</title> - <!-- Bootstrap CSS --> - <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> - <!-- Custom style --> + <title>Menu with Submenus</title> + <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> <style> - .card-header, .non-collapse-item { - padding: 0.75rem 1.25rem; - margin-bottom: 0; - background-color: rgba(0,0,0,.03); - border-bottom: 1px solid rgba(0,0,0,.125); - cursor: pointer; + .menu-container { + max-height: 400px; + overflow-y: auto; } - .non-collapse-item p { - margin-bottom: 0; - text-align: center; + .submenu-container { + display: none; + position: absolute; + left: 100%; + top: 0; + min-width: 200px; + z-index: 10; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); } - .card-body p { - padding-left: 20px; + .submenu-item .submenu-container { + left: 100%; + top: 0; } - .submenu-background { - background-color: #f8f9fa; - padding: 10px; - border-radius: 5px; - margin-top: 5px; + .menu-item:hover > .submenu-container { + display: block; + } + .submenu-item:hover > .submenu-container { + display: block; + } + .menu-item { + width: 150px; } - </style> </head> <body> -<!-- Recursive menu fragment --> -<div th:fragment="menuFragment(menuList, isTopLevel)"> - <div th:each="menu, menuStat: ${menuList}"> - <!-- Items with submenus --> - <div th:if="${menu.subMenus.size() != 0 && menu.subMenus != null}"> - <div th:if="${isTopLevel}" class="card"> - <div class="card-header"> - <h4 class="mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" th:data-target="| #collapse${menuStat.index} |"> - <span th:src="${menu.url}" th:text="${menu.name}">Menu Name</span> - </button> - </h4> - </div> - - <div th:id="|collapse${menuStat.index}|" class="collapse" data-parent="#accordion"> - <div class="card-body"> - <div th:replace="this :: menuFragment(${menu.subMenus}, false)"></div> +<div class="container mx-auto p-4 flex justify-center items-center min-h-screen"> + <div class="menu-container bg-white rounded-md shadow-lg"> + <div th:fragment="menuFragment(menuList, isTopLevel)"> + <div th:each="menu, menuStat : ${menuList}" class="relative"> + <div th:if="${menu.subMenus.size() != 0 && menu.subMenus != null}"> + <div th:if="${isTopLevel}" class="bg-gray-100 border-b border-gray-200 cursor-pointer hover-effect menu-item"> + <h4 class="m-0 p-2 flex justify-between items-center"> + <div class="text-gray-800 hover:text-gray-600" th:attr="onclick=|window.location.href='${menu.url}'|" th:text="${menu.name}">Menu Name</div> + </h4> + <div class="submenu-container"> + <div class="bg-white submenu-background" th:replace="this :: menuFragment(${menu.subMenus}, false)"></div> + </div> + </div> + <div th:unless="${isTopLevel}" class="submenu-background hover:bg-blue-300 hover-effect submenu-item"> + <div class="p-2 text-gray-800 hover:text-gray-600" th:attr="onclick=|window.location.href='${menu.url}'|" th:text="${menu.name}">Submenu Name</div> + <div class="submenu-container"> + <div th:replace="this :: menuFragment(${menu.subMenus}, false)"></div> + </div> </div> </div> - </div> - <div th:unless="${isTopLevel}" class="submenu-background"> - <button class="btn btn-link" type="button" data-toggle="collapse" th:data-target="| #collapseSub${menuStat.index} |"> - <span th:src="${menu.url}" th:text="${menu.name}">Submenu Name</span> - </button> - <div th:id="|collapseSub${menuStat.index}|" class="collapse"> - <div th:replace="this :: menuFragment(${menu.subMenus}, false)"></div> + <div th:if="${menu.subMenus.size() == 0}"> + <a class="block p-2 text-gray-800 hover:text-gray-600 hover-effect menu-item" th:href="${menu.url}" th:text="${menu.name}">Menu Item</a> </div> </div> </div> - - <!-- No submenu items --> - <div th:if="${menu.subMenus.size() == 0}"> - <a th:src="${menu.url}" th:text="${menu.name}">Menu Item</a> - </div> </div> -</div> -<div id="main" class="container-fluid"> - <div id="main_nav" class="d-inline-block"> - <div id="accordion"> - <!-- Call the recursive fragment --> - <div th:replace="this :: menuFragment(${menus}, true)"></div> - </div> - <div class="logout-button-container"> - <button id="logoutButton" class="btn btn-danger">log out</button> - </div> + <div id="main_nav" class="mt-4"> + <div th:replace="this :: menuFragment(${menus}, true)"></div> + <button id="logoutButton" class="mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition duration-300 ease-in-out">Log out</button> </div> </div> -<!-- Bootstrap JS, Popper.js, and jQuery --> -<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> -<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script> -<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> <script> document.addEventListener('DOMContentLoaded', function() { - var clickableItems = document.querySelectorAll('[src]'); - clickableItems.forEach(function(item) { - item.addEventListener('click', function() { - var url = this.getAttribute('src'); - if (url) { - window.location.href = url; - } + document.querySelectorAll('.menu-item, .submenu-item').forEach(function(item) { + item.addEventListener('mouseenter', function() { + let submenu = this.querySelector('.submenu-container'); + if(submenu) submenu.classList.remove('hidden'); + }); + item.addEventListener('mouseleave', function() { + let submenu = this.querySelector('.submenu-container'); + if(submenu) submenu.classList.add('hidden'); }); }); + var logoutButton = document.getElementById('logoutButton'); logoutButton.addEventListener('click', function() { sessionStorage.clear(); localStorage.clear(); - window.location.href = '/casbin'; + window.location.href = '/'; }); }); </script> + </body> </html>