springboot學習筆記:11.springboot+shiro+mysql+mybatis(通用mapper)+freemarker+ztree+layui實現通用的java后台管理系統(權限管理+用戶管理+菜單管理)


一.前言

經過前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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM