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

一.前言

通過前10篇文章,咱們已經能夠快速搭建一個springboot的web項目;前端

今天,咱們在上一節基礎上繼續集成shiro框架,實現一個能夠通用的後臺管理系統;包括用戶管理,角色管理,菜單管理三大系統經常使用管理模塊;java

二.數據庫表準備:

要想實現用戶管理+角色管理+菜單管理三大模塊,基本上咱們經常使用的解決方案就是以下五個表(sql腳本在最後):mysql

三.集成shiro和配置

1.添加pom依賴。git

<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.javagithub

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定義說明 一、一個URL能夠配置多個Filter,使用逗號分隔 二、當設置多個過濾器時,所有驗證經過,才視爲經過
     * 三、部分過濾器可指定參數,如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.javaweb

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.登陸、退出、權限限制spring

登陸:subject.login(token);sql

退出:SecurityUtils.getSubject().logout();數據庫

在方法前使用shiro註解實現權限校驗,如:@RequiresPermissions(value = {"用戶管理"}) 表示當前用戶必須擁有用戶管理的權限;apache

4、前端實現及效果展現

一、登陸

請求http://localhost:8080/blogmanager/

被shiro攔截後自動跳轉到登陸界面;

項目地址能夠在配置文件中配置:

 

源碼:src\main\resources\templates\login.ftl

用戶名:admin

密碼:1

 

 

 二、系統管理-菜單管理

菜單管理頁面源碼:src\main\resources\templates\power\menu.ftl

裏面使用了ztree實現的菜單的新建、編輯、刪除;

菜單管理的後臺接口:com.zjt.web.MenuController.java

 

注意一級菜單在頂部顯示,且一級菜單名不可爲純數字;

二級三級菜單在左側顯示,且最多隻能到三級菜單;

 

 三、系統管理-角色管理

src\main\resources\templates\power\role.ftl

com.zjt.web.RoleAdminController.java

頁面使用了jqgrid表格插件;

並能夠設置每一個角色對應的菜單權限:

四、系統管理-用戶管理

 src\main\resources\templates\power\user.ftl

 com.zjt.web.UserAdminController.java

 

選擇行後能夠設置角色:

 

 5、後記

 本後臺管理系統可做爲通用的後臺管理系統,她簡單純淨;內置完善的菜單管理+角色管理+用戶管理;拿來即用;

使用技術涉及:

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

相關文章
相關標籤/搜索