一.前言

经过前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

springboot学习笔记:11.springboot+shiro+mysql+mybatis(通用mapper)+freemarker+ztree+layui实现通用的java后台管理系统(权限管理+用户管理+菜单管理)的更多相关文章

  1. SpringBoot学习笔记(11)-----SpringBoot中使用rabbitmq,activemq消息队列和rest服务的调用

    1. activemq 首先引入依赖 pom.xml文件 <dependency> <groupId>org.springframework.boot</groupId& ...

  2. springboot学习笔记-5 springboot整合shiro

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和sh ...

  3. SpringBoot学习笔记二之Spring整合Mybatis

    原文链接: https://www.toutiao.com/i6803235766274097678/ 在learn-admin-component子工程中加入搭建环境所需要的具体依赖(因为比较长配置 ...

  4. SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理

    在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...

  5. SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]

    https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...

  6. springboot学习笔记-6 springboot整合RabbitMQ

    一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...

  7. 【转】SpringBoot学习笔记(7) SpringBoot整合Dubbo(使用yml配置)

    http://blog.csdn.net/a67474506/article/details/61640548 Dubbo是什么东西我这里就不详细介绍了,自己可以去谷歌 SpringBoot整合Dub ...

  8. SpringBoot学习笔记(16)----SpringBoot整合Swagger2

    Swagger 是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务 http://swagger.io Springfox的前身是swagger-springmvc,是 ...

  9. SpringBoot学习笔记(15)----SpringBoot使用Druid

    直接访问Druid官网wiki,有详细教程,地址如下: SpringBoot支持Druid地址:https://github.com/alibaba/druid/tree/master/druid-s ...

随机推荐

  1. Vundle安装及使用

    Vundle是vim上的插件管理器.只需要在.vimrc添加上控件名,Vundle可以帮我们下载到插件文件夹/Users/{username}/.vim/bundle中. 有一个vim插件的资源网站, ...

  2. 因子分析和PCA总结

    因子分析和PCA 定义 因子分析就是数据降维工具.从一组相关变量中删除冗余或重复,把相关的变量放在一个因子中,实在不相关的因子有可能被删掉.用一组较小的“派生”变量表示相关变量,这个派生就是新的因子. ...

  3. ERNIE:知识图谱结合BERT才是「有文化」的语言模型

    自然语言表征模型最近受到非常多的关注,很多研究者将其视为 NLP 最重要的研究方向之一.例如在大规模语料库上预训练的 BERT,它可以从纯文本中很好地捕捉丰富的语义模式,经过微调后可以持续改善不同 N ...

  4. Java if、switch语句,break,case,类型转换、常量、赋值比较、标识符(2)

    if语句: /* if else 结构 简写格式: 变量 = (条件表达式)?表达式1:表达式2: 三元运算符: 好处:可以简化if else代码. 弊端:因为是一个运算符,所以运算完必须要有一个结果 ...

  5. 卡常的编译命令(含O2优化)

    不解释,直接来 //包括O2,O3之类的编译命令 //直接copy and paste #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma ...

  6. excel 导出长数据 变成科学计数 解决办法

    加 “\t”

  7. 17.3.10--关于C元的变量类型所占字节问题和类型转化

    在C语言并没有对于严格规定short,int  long所占字节,只是做了宽泛要求:short:至少连个字节 int建议为一个机器字长,32位环境下机器字长是4个字节,64位环境机器字长是8个字节 s ...

  8. 蓝桥杯2015-省赛-C/C++-A组2题 星系炸弹

    在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标.每个炸弹都可以设定多少天之后爆炸.比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸.有一个贝塔 ...

  9. 个人训练记录(UPD 9.16)

    本文章记录一些较难的题,摘自自己的blog中的其他文章.也有些单独成章有点浪费的题也写在里面了. 2019.7.15-2019.7.21 1182F(2900) 题意:求在区间 \([a,b]\) 中 ...

  10. 4.windows-oracle实战第四课 -表的查询

    所有语句均为安装oracle数据库后scott的默认表emp,dept等表 1.自己插入自己:insert into 表名 (字段)select *from 表名 2.去除重复行: select di ...