经过长时间的学习和调试,终于实现初步效果,现在将部分代码整理如下:
一、数据库代码
分别建立三张表user(用户信息表),role(角色表),rolemenu(角色菜单关联表),menu(菜单表)。表结构如下:
CREATE TABLE `user` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名', `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码', `realname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '真实姓名', `remark` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '说明', `is_delete` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否删除', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', `order_no` int(11) NULL DEFAULT NULL COMMENT '排序', `role_id` int(11) NULL DEFAULT NULL COMMENT '角色', `image_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `order_no` int(11) NULL DEFAULT NULL COMMENT '排序号', `remark` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '说明', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `rolemenu` ( `id` int(11) NOT NULL AUTO_INCREMENT, `menu_id` int(11) NULL DEFAULT NULL, `role_id` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `FKhayg4ib6v7h1wyeyxhq6xlddq`(`menu_id`) USING BTREE, INDEX `FKsonb0rbt2u99hbrqqvv3r0wse`(`role_id`) USING BTREE, CONSTRAINT `rolemenu_ibfk_1` FOREIGN KEY (`menu_id`) REFERENCES `menu` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `rolemenu_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `t_a_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT) ENGINE = InnoDB AUTO_INCREMENT = 84 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `menu` ( `id` int(11) NOT NULL AUTO_INCREMENT, `div_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `icon` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `p_id` int(11) NULL DEFAULT NULL, `permissions` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `state` int(11) NULL DEFAULT NULL, `type` int(11) NULL DEFAULT NULL, `url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `order_no` int(11) NOT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
然后建立联合查询,实现根据用户名查询相关菜单名称和链接
SELECT username,`password`,a.role_id,menu_id,c.div_id,c.icon,c.name,c.p_id,c.permissions,c.url from `user` aright join rolemenu b on a.role_id=b.role_idinner join menu c on b.menu_id=c.idWHERE username='admin'
二、导入依赖
<!--添加对shior的支持 --><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version></dependency><!--添加对shior的支持 --><!-- 添加thymeleaf整合shiro标签 依赖 --><dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version></dependency><!-- 添加thymeleaf整合shiro标签 依赖 -->
三、ShiroConfig配置
package pers.gl.config;import java.util.LinkedHashMap;import java.util.Map;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;/*** Shiro配置类** 1创建 ShiroFilterFactoryBean** 2.登陆 安全管理器** 3*/@Configurationpublic class ShiroConfig {/** * ShiroFilterFactoryBean 处理拦截资源文件问题。注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles * */@Beanpublic ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// 必须设置 SecurityManagershiroFilterFactoryBean.setSecurityManager(securityManager);// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面// 设置 没有登陆 跳转的页面shiroFilterFactoryBean.setLoginUrl("/login");// 设置 没有登陆 跳转的页面// 拦截器Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();// 配置不会被拦截的链接 顺序判断filterChainDefinitionMap.put("/static/**", "anon");filterChainDefinitionMap.put("/login", "anon");// 配置不会被拦截的链接 顺序判断// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/logout", "logout");// 退出之后跳到 /这个路径 上面// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->// filterChainDefinitionMap.put("/**", "authc");// authc需要 登陆才能访问filterChainDefinitionMap.put("/admin/**", "authc");filterChainDefinitionMap.put("/houtai/**", "authc");// authc需要 登陆才能访问shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/** * 创建 安全管理器 SecurityManager * * @return */@Beanpublic SecurityManager securityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置realm.securityManager.setRealm(myRealm());return securityManager;}/** * 身份认证realm; (这个需要自己写,账号密码校验;权限等) * * @return */@Beanpublic MyRealm myRealm() {MyRealm myRealm = new MyRealm();return myRealm;}/** * Shiro生命周期处理器 * * @return */@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 * * @return */@Bean@DependsOn({ "lifecycleBeanPostProcessor" })public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargetClass(true);return advisorAutoProxyCreator;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());return authorizationAttributeSourceAdvisor;}/** * 配置 ShiroDialect 用于thymeleaf 和shiro标签配合使用 * * @return */@Beanpublic ShiroDialect getShiroDialect() {return new ShiroDialect();}}
四、MyRealm自定义Realm
package pers.gl.config;import java.util.List;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import pers.gl.model.Menu;import pers.gl.model.User;import pers.gl.service.MenuService;import pers.gl.service.RoleMenuService;import pers.gl.service.UserService;/*** 自定义Realm**/public class MyRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Autowiredprivate RoleMenuService roleMenuService;@Autowiredprivate MenuService menuService;/** * 授权 // */@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String name = (String) SecurityUtils.getSubject().getPrincipal();User user = userService.findByName(name);// 有了用户可以拿到,角色, 有角色,就有对应的菜单 list集合。--- permissionsSystem.out.println(user);// 这个角色对应 的菜单List<Menu> roleMenuList = menuService.findMenuByRoleid(user.getRole_id());SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();for (Menu menu : roleMenuList) {info.addStringPermission(menu.getPermissions().trim());}// 这个角色对应 的菜单//// 设置角色//// Set<String> roles=new HashSet<String>();//// roles.add(user.getRole().getName());//// info.setRoles(roles);//// 设置角色//return info;}/** * 权限认证 */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String name = (String) token.getPrincipal();User user = userService.findByName(name);if (user != null) {AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "xxx");return authcInfo;} else {return null;}}}
五、登录退出Controller
package pers.gl.controller;import javax.annotation.Resource;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import net.sf.json.JSONObject;import pers.gl.model.User;import pers.gl.service.UserService;import pers.gl.util.CryptographyUtil;@Controller@RequestMapping("/user")public class UserController {@Resourceprivate UserService userService;@ResponseBody@RequestMapping("/login")public JSONObject login(String username, String password) throws Exception {JSONObject result = new JSONObject();// 获取 subjectSubject subject = SecurityUtils.getSubject();// 封装用户数据UsernamePasswordToken token = new UsernamePasswordToken(username, CryptographyUtil.md5(password, "java"));// 执行登陆 shiro的登陆try {subject.login(token);result.put("success", true);result.put("msg", "登陆成功");User user = userService.findByName(username);SecurityUtils.getSubject().getSession().setAttribute("currentUser", user); // 把当前用户信息存到session中} catch (UnknownAccountException e) {result.put("success", false);result.put("msg", "用户名不存在");} catch (IncorrectCredentialsException e) {result.put("success", false);result.put("msg", "密码错误");}return result;}/** * 注销 /user/logout * * @throws Exception */@RequestMapping("/logout")public String logout() throws Exception {SecurityUtils.getSubject().logout(); // shiro的退出return "redirect:/login";}}
六、页面跳转Controller
package pers.gl.controller;import java.util.List;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.SecurityUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import pers.gl.model.User;import pers.gl.model.UserMenu;import pers.gl.service.UserService;@Controllerpublic class IndexController {@Autowiredprivate UserService userService;// 定位到登录页面@GetMapping("/login")public String toLogin() {return "/login";}/** * 后台主页 */@RequestMapping("/admin/main")public String admin_main(Model model, HttpServletRequest req) throws Exception {User currentUser1 = (User) SecurityUtils.getSubject().getSession().getAttribute("currentUser");System.out.println(currentUser1);List<UserMenu> menuList = userService.findMenuByUsername(currentUser1.getUsername());model.addAttribute("treeList", menuList);System.out.println(menuList);return "/admin/main";}}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。