一.前言

经过前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. 根据pdf文件获取标题等信息

    根据 kdd2019的 pdf文件, 生成索引文档. 代码如下: for fname in ` ls pdfs/*.pdf`; do title=$(mdls -name kMDItemTitle - ...

  2. 吴裕雄--天生自然 JAVASCRIPT开发学习: 验证 API

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> ...

  3. 信号分析——从傅里叶变化到FFT

    我们眼中的世界就像皮影戏的大幕布,幕布的后面有无数的齿轮,大齿轮带动小齿轮,小齿轮再带动更小的. 在最外面的小齿轮上有一个小人——那就是我们自己. 我们只看到这个小人毫无规律的在幕布前表演,却无法预测 ...

  4. Java中static变量作用和用法详解

    static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static ...

  5. session和token区别

    分布式系统认证/授权目前分布式系统存在两种常用的认证授权方式:分布式session和token 1.session的概念 session中存放登录用户的个人信息,创建session时,随机生成一个se ...

  6. fastDFS 文件系统搭建

    1.单机版 https://www.cnblogs.com/chiangchou/p/fastdfs.html#_label3_0 2.集群版

  7. SEO优化技巧

    一.搜索引擎工作原理 当我们在输入框中输入关键词,点击搜索或查询时,然后得到结果.深究其背后的故事,搜索引擎做了很多事情. 在搜索引擎网站,比如百度,在其后台有一个非常庞大的数据库,里面存储了海量的关 ...

  8. LeetCode——15. 三数之和

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  9. Spring Boot 默认的指标数据从哪来的?

    了解有关 Spring Boot 默认指标及其来源的更多信息. 您是否注意到 Spring Boot 和 Micrometer 为您的应用生成的所有默认指标?如果没有 - 您可以将 actuator  ...

  10. springmvc register过程

    福建SEO:首先在AbstractHandlerMethodMapping中,在afterPropertiesSet这个钩子函数中,先初始化handlerMethods. 在detectHandler ...