一.前言
經過前10篇文章,我們已經可以快速搭建一個springboot的web項目;
今天,我們在上一節基礎上繼續集成shiro框架,實現一個可以通用的后台管理系統;包括用戶管理,角色管理,菜單管理三大系統常用管理模塊;
二.數據庫表准備:
要想實現用戶管理+角色管理+菜單管理三大模塊,基本上我們常用的解決方案就是如下五個表(sql腳本在最后):
三.集成shiro和配置
1.添加pom依賴。
<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>
2.編輯shiro配置類:ShiroConfig.java
package com.zjt.config; import com.zjt.realm.MyRealm; 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.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * @Author: Zhaojiatao * @Description: Shiro配置類 * @Date: Created in 2018/2/8 13:29 * @param */ @Configuration public class ShiroConfig { /** * ShiroFilterFactoryBean 處理攔截資源文件問題。 * 注意:單獨一個ShiroFilterFactoryBean配置是或報錯的,以為在 * 初始化ShiroFilterFactoryBean的時候需要注入:SecurityManager * * Filter Chain定義說明 1、一個URL可以配置多個Filter,使用逗號分隔 2、當設置多個過濾器時,全部驗證通過,才視為通過 * 3、部分過濾器可指定參數,如perms,roles * */ @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 //shiroFilterFactoryBean.setLoginUrl("/login.ftl"); //配置退出過濾器,其中的具體的退出代碼Shiro已經替我們實現了 shiroFilterFactoryBean.setLoginUrl("/tologin"); shiroFilterFactoryBean.setUnauthorizedUrl("/tologin"); // 攔截器. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //配置記住我或認證通過可以訪問的地址(配置不會被攔截的鏈接 順序判斷) filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/user/login", "anon"); filterChainDefinitionMap.put("/drawImage", "anon"); // 配置退出過濾器,其中的具體的退出代碼Shiro已經替我們實現了 filterChainDefinitionMap.put("/admin/user/logout", "logout"); // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了; // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設置realm. securityManager.setRealm(myRealm()); //注入記住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } /** * 身份認證realm; (這個需要自己寫,賬號密碼校驗;權限等) * * @return */ @Bean public MyRealm myRealm() { MyRealm myRealm = new MyRealm(); return myRealm; } /** * Shiro生命周期處理器 * @return */ @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor(); } /** * 開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP掃描使用Shiro注解的類,並在必要時進行安全邏輯驗證 * 配置以下兩個bean(DefaultAdvisorAutoProxyCreator(可選)和AuthorizationAttributeSourceAdvisor)即可實現此功能 * 不要使用 DefaultAdvisorAutoProxyCreator 會出現二次代理的問題,這里不詳述 * @return */ /* @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; }*/ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); return authorizationAttributeSourceAdvisor; } /** * cookie對象; * 記住密碼實現起來也是比較簡單的,主要看下是如何實現的。 * @return */ @Bean public SimpleCookie rememberMeCookie(){ System.out.println("ShiroConfiguration.rememberMeCookie()"); //這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //<!-- 記住我cookie生效時間30天 ,單位秒;--> simpleCookie.setMaxAge(259200); return simpleCookie; } /** * cookie管理對象; * @return */ @Bean public CookieRememberMeManager rememberMeManager(){ System.out.println("ShiroConfiguration.rememberMeManager()"); CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); return cookieRememberMeManager; } }
3.實現自定義MyRealm.java
package com.zjt.realm; import com.zjt.entity.Tmenu; import com.zjt.entity.Trole; import com.zjt.entity.Tuser; import com.zjt.mapper.TmenuMapper; import com.zjt.mapper.TroleMapper; import com.zjt.mapper.TuserMapper; import com.zjt.mapper.TuserroleMapper; 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 tk.mybatis.mapper.entity.Example; import javax.annotation.Resource; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 自定義Realm * @author zjt * */ public class MyRealm extends AuthorizingRealm{ @Resource private TuserMapper tuserMapper; @Resource private TroleMapper troleMapper; @Resource private TuserroleMapper tuserroleMapper; @Resource private TmenuMapper tmenuMapper; /** * 授權 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String userName=(String) SecurityUtils.getSubject().getPrincipal(); //User user=userRepository.findByUserName(userName); //根據用戶名查詢出用戶記錄 Example tuserExample=new Example(Tuser.class); tuserExample.or().andEqualTo("userName",userName); Tuser user=tuserMapper.selectByExample(tuserExample).get(0); SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); //List<Role> roleList=roleRepository.findByUserId(user.getId()); List<Trole> roleList = troleMapper.selectRolesByUserId(user.getId()); Set<String> roles=new HashSet<String>(); if(roleList.size()>0){ for(Trole role:roleList){ roles.add(role.getName()); //List<Tmenu> menuList=menuRepository.findByRoleId(role.getId()); //根據角色id查詢所有資源 List<Tmenu> menuList=tmenuMapper.selectMenusByRoleId(role.getId()); for(Tmenu menu:menuList){ info.addStringPermission(menu.getName()); // 添加權限 } } } info.setRoles(roles); return info; } /** * 權限認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName=(String)token.getPrincipal(); //User user=userRepository.findByUserName(userName); Example tuserExample=new Example(Tuser.class); tuserExample.or().andEqualTo("userName",userName); Tuser user=tuserMapper.selectByExample(tuserExample).get(0); if(user!=null){ AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xxx"); return authcInfo; }else{ return null; } } }
4.登錄、退出、權限限制
登錄:subject.login(token);
退出:SecurityUtils.getSubject().logout();
在方法前使用shiro注解實現權限校驗,如:@RequiresPermissions(value = {"用戶管理"}) 表示當前用戶必須擁有用戶管理的權限;
四、前端實現及效果展示
1、登錄
請求http://localhost:8080/blogmanager/
被shiro攔截后自動跳轉到登錄界面;
項目地址可以在配置文件中配置:
源碼:src\main\resources\templates\login.ftl
用戶名:admin
密碼:1
2、系統管理-菜單管理
菜單管理頁面源碼:src\main\resources\templates\power\menu.ftl
里面使用了ztree實現的菜單的新建、編輯、刪除;
菜單管理的后台接口:com.zjt.web.MenuController.java
注意一級菜單在頂部顯示,且一級菜單名不可為純數字;
二級三級菜單在左側顯示,且最多只能到三級菜單;
3、系統管理-角色管理
src\main\resources\templates\power\role.ftl
com.zjt.web.RoleAdminController.java
頁面使用了jqgrid表格插件;
並可以設置每個角色對應的菜單權限:
4、系統管理-用戶管理
src\main\resources\templates\power\user.ftl
com.zjt.web.UserAdminController.java
選擇行后可以設置角色:
五、后記
本后台管理系統可作為通用的后台管理系統,她簡單純凈;內置完善的菜單管理+角色管理+用戶管理;拿來即用;
使用技術涉及:
springboot+springmvc+mysql+mybatis+通用mapper+分頁插件+shiro+freemarker+layui+ztree
其中layui模板使用的是layuicms2.0
本項目源碼:
https://github.com/zhaojiatao/springboot-zjt-chapter10-springboot-mysql-mybatis-shiro-freemarker-layui.git
sql腳本含在項目sql文件夾中
項目訪問地址和端口在配置文件中:application-dev.properties