一.前言
经过前10篇文章,我们已经可以快速搭建一个springboot的web项目;
今天,我们在上一节基础上继续集成shiro框架,实现一个可以通用的后台管理系统;包括用户管理,角色管理,菜单管理三大系统常用管理模块;
二.数据库表准备:
要想实现用户管理+角色管理+菜单管理三大模块,基本上我们常用的解决方案就是如下五个表(sql脚本在最后):
三.集成shiro和配置
1.添加pom依赖。
org.apache.shiro
shiro-core
1.4.0
org.apache.shiro
shiro-spring
1.4.0
2.编辑shiro配置类:ShiroConfig.java
packagecom.zjt.config;importcom.zjt.realm.MyRealm;importorg.apache.shiro.mgt.SecurityManager;importorg.apache.shiro.spring.LifecycleBeanPostProcessor;importorg.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;importorg.apache.shiro.spring.web.ShiroFilterFactoryBean;importorg.apache.shiro.web.mgt.CookieRememberMeManager;importorg.apache.shiro.web.mgt.DefaultWebSecurityManager;importorg.apache.shiro.web.servlet.SimpleCookie;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.LinkedHashMap;importjava.util.Map;/*** @Author: Zhaojiatao
* @Description: Shiro配置类
* @Date: Created in 2018/2/8 13:29
*@param
*/@Configurationpublic classShiroConfig {/*** ShiroFilterFactoryBean 处理拦截资源文件问题。
* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
*
* Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
* 3、部分过滤器可指定参数,如perms,roles
**/@BeanpublicShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean= newShiroFilterFactoryBean();//必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);//如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面//shiroFilterFactoryBean.setLoginUrl("/login.ftl");//配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
shiroFilterFactoryBean.setLoginUrl("/tologin");
shiroFilterFactoryBean.setUnauthorizedUrl("/tologin");//拦截器.
Map filterChainDefinitionMap = new LinkedHashMap();//配置记住我或认证通过可以访问的地址(配置不会被拦截的链接 顺序判断)
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/user/login", "anon");
filterChainDefinitionMap.put("/drawImage", "anon");//配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/admin/user/logout", "logout");//:这是一个坑呢,一不小心代码就不好使了;//
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);returnshiroFilterFactoryBean;
}
@BeanpublicSecurityManager securityManager() {
DefaultWebSecurityManager securityManager= newDefaultWebSecurityManager();//设置realm.
securityManager.setRealm(myRealm());//注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());returnsecurityManager;
}/*** 身份认证realm; (这个需要自己写,账号密码校验;权限等)
*
*@return
*/@BeanpublicMyRealm myRealm() {
MyRealm myRealm= newMyRealm();returnmyRealm;
}/*** Shiro生命周期处理器
*@return
*/@BeanpublicLifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return newLifecycleBeanPostProcessor();
}/*** 开启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;
}*/@BeanpublicAuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor= newAuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());returnauthorizationAttributeSourceAdvisor;
}/*** cookie对象;
* 记住密码实现起来也是比较简单的,主要看下是如何实现的。
*@return
*/@BeanpublicSimpleCookie rememberMeCookie(){
System.out.println("ShiroConfiguration.rememberMeCookie()");//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");//
simpleCookie.setMaxAge(259200);returnsimpleCookie;
}/*** cookie管理对象;
*@return
*/@BeanpublicCookieRememberMeManager rememberMeManager(){
System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager= newCookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());returncookieRememberMeManager;
}
}
3.实现自定义MyRealm.java
packagecom.zjt.realm;importcom.zjt.entity.Tmenu;importcom.zjt.entity.Trole;importcom.zjt.entity.Tuser;importcom.zjt.mapper.TmenuMapper;importcom.zjt.mapper.TroleMapper;importcom.zjt.mapper.TuserMapper;importcom.zjt.mapper.TuserroleMapper;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.SimpleAuthenticationInfo;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importtk.mybatis.mapper.entity.Example;importjavax.annotation.Resource;importjava.util.HashSet;importjava.util.List;importjava.util.Set;/*** 自定义Realm
*@authorzjt
**/
public class MyRealm extendsAuthorizingRealm{
@ResourceprivateTuserMapper tuserMapper;
@ResourceprivateTroleMapper troleMapper;
@ResourceprivateTuserroleMapper tuserroleMapper;
@ResourceprivateTmenuMapper tmenuMapper;/*** 授权*/@OverrideprotectedAuthorizationInfo 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=newSimpleAuthorizationInfo();//List roleList=roleRepository.findByUserId(user.getId());
List roleList =troleMapper.selectRolesByUserId(user.getId());
Set roles=new HashSet();if(roleList.size()>0){for(Trole role:roleList){
roles.add(role.getName());//List menuList=menuRepository.findByRoleId(role.getId());//根据角色id查询所有资源
List menuList=tmenuMapper.selectMenusByRoleId(role.getId());for(Tmenu menu:menuList){
info.addStringPermission(menu.getName());//添加权限
}
}
}
info.setRoles(roles);returninfo;
}/*** 权限认证*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throwsAuthenticationException {
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");returnauthcInfo;
}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项目中集成Shiro框架,实现用户、角色、菜单管理功能。通过添加Shiro相关依赖,配置ShiroFilterFactoryBean和自定义Realm,实现了权限控制和认证。此外,还展示了前端页面的实现,利用ztree和layui构建了管理界面。
200

被折叠的 条评论
为什么被折叠?



