SpringBoot集成Shiro安全框架

  • 1.shiro的定义
  • 2.SpringBoot集成shiro的步骤
  • 3.完成的效果

1.shiro的定义

1.shiro的作用
认证、授权、加密、会话管理、Web集成、缓存

2.shiro的名词

Authentication:身份认证/登录,验证用户是不是拥有相应的身份
Authorization:授权,即权限 管理,验证某个人已经登录的人是否拥有某些权限
Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前所有的信息都是在会话中。。
Cryptography:加密,保护数据的安全性,密码加密
Web Support:Web支持,可以非常容易的集成到web环境
Caching:缓存,比如用户登录之后,他的用户信息,权限不必每次去查
Concurrency:shiro支持多线程应用兵法验证,即如果在一个线程中开启另外一个线程,权限会自动传递过去
Testing:提供测试支持
Run AS:允许一个用户假装另一个用户(如果他们允许)的身份进行访问
Remember Me:记住我,这是一个常见的功能,即一次登录后,下次再来的话就不用登录了
记住一点,Shiro不会去维护用户、维护权限:这些需要我们自己去设计/提供,然后通过相应的接口注入给Shiro即可!

3.shiro的架构

Subject,Subject其实代表的就是当前正在执行操作的用户,只不过因为“User”一般指代人,但是一个“Subject”可以是人,也可以是任何的第三方系统,服务账号等任何其他正在和当前系统交互的第三方软件系统。
所有的Subject实例都被绑定到一个SecurityManager,如果你和一个Subject交互,所有的交互动作都会被转换成Subject与SecurityManager的交互。

SecurityManager。SecurityManager是Shiro的核心,他主要用于协调Shiro内部各种安全组件,不过我们一般不用太关心SecurityManager,对于应用程序开发者来说,主要还是使用Subject的API来处理各种安全验证逻辑。

Realm,这是用于连接Shiro和客户系统的用户数据的桥梁。一旦Shiro真正需要访问各种安全相关的数据(比如使用用户账户来做用户身份验证以及权限验证)时,他总是通过调用系统配置的各种Realm来读取数据。

2.SpringBoot集成shiro的步骤

1.添加maven依赖

 <!-- shiro整合springboot所需相关依赖--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency><!-- 兼容于thymeleaf的shiro --><dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version></dependency><!--end.......-->

2.新建缓存文件
ehcache-shiro.xml


<ehcache updateCheck="false" name="cacheManagerConfigFile"><!--name:缓存名称。maxElementsInMemory:缓存最大个数。eternal:对象是否永久有效,一但设置了,timeout将不起作用。timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。maxElementsOnDisk:硬盘最大缓存个数。diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。clearOnFlush:内存数量最大时是否清除。--><defaultCache maxElementsInMemory="10000" eternal="false"timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false"diskPersistent="false" diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"/><!-- 登录记录程序锁定1分钟 --><cache name="shiro-activeSessionCache" eternal="false"maxElementsInMemory="10000" overflowToDisk="false" timeToIdleSeconds="0"timeToLiveSeconds="0" statistics="true"/>
</ehcache>

3.重要的shiro配置类
不需要完全记住,只需要修改其中的一小部分

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;/*** @ Author     :Zgq* @ Date       :Created in 18:22 2019/6/11* @ Description:shiro的配置类* @ Modified By:* @Version: $*/
@Configuration
public class ShiroConfig {/**唯一需要修改的地方,有注释* ShiroFilterFactoryBean 处理拦截资源文件问题。* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,* 因为在初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager* Filter Chain定义说明* 1、一个URL可以配置多个Filter,使用逗号分隔* 2、当设置多个过滤器时,全部验证通过,才视为通过* 3、部分过滤器可指定参数,如perms,roles*/@Beanpublic ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// 必须设置 SecurityManagershiroFilterFactoryBean.setSecurityManager(securityManager);// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面//访问的是后端url地址为 /login的接口,/未登录页面,会跳转到登录页面shiroFilterFactoryBean.setLoginUrl("/login");// 登录成功后要跳转的链接shiroFilterFactoryBean.setSuccessUrl("/index");// 未授权界面;,基于AOP拦截,都会到登录页面shiroFilterFactoryBean.setUnauthorizedUrl("/login");// 拦截器.Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();// 配置不会被拦截的链接 顺序判断,anon放开,不会拦截,authc会拦截//静态资源不能被拦截filterChainDefinitionMap.put("/assets/**", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/images/**", "anon");filterChainDefinitionMap.put("/fonts/**", "anon");filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/userLogin", "anon");// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/logout", "logout");//配置某个url需要某个权限码filterChainDefinitionMap.put("/hello", "perms[how_are_you]");// 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->filterChainDefinitionMap.put("/**", "authc");//配置记住我或认证通过可以访问的地址filterChainDefinitionMap.put("/index", "user");
//        filterChainDefinitionMap.put("/", "user");System.out.println("Shiro拦截器工厂类注入成功");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** 缓存* @return*/@Beanpublic EhCacheManager getEhCacheCache() {EhCacheManager em = new EhCacheManager();em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");return em;}/*** 代理* @return*/@Beanpublic DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();daap.setProxyTargetClass(true);return daap;}@Beanpublic DefaultWebSessionManager getDefaultWebSessionManager() {DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();defaultWebSessionManager.setSessionDAO(getMemorySessionDAO());defaultWebSessionManager.setGlobalSessionTimeout(1 * 60 * 60 * 1000);defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);defaultWebSessionManager.setSessionIdCookieEnabled(true);defaultWebSessionManager.setSessionIdCookie(getSimpleCookie());return defaultWebSessionManager;}@Beanpublic MemorySessionDAO getMemorySessionDAO() {MemorySessionDAO memorySessionDAO = new MemorySessionDAO();memorySessionDAO.setSessionIdGenerator(javaUuidSessionIdGenerator());return memorySessionDAO;}@Beanpublic JavaUuidSessionIdGenerator javaUuidSessionIdGenerator() {return new JavaUuidSessionIdGenerator();}/*** cookie对象* @return*/@Beanpublic SimpleCookie getSimpleCookie() {SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("security.session.id");//<!-- 记住我cookie生效时间30天 ,单位秒;-->simpleCookie.setMaxAge(259200);simpleCookie.setPath("/");return simpleCookie;}/*** cookie管理对象;* @return*//*@Beanpublic CookieRememberMeManager rememberMeManager(){System.out.println("ShiroConfiguration.rememberMeManager()");CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(getSimpleCookie());return cookieRememberMeManager;}*/@Beanpublic LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 注入 securityManager*/@Bean(name = "securityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager(ShiroRealm shiroRealm) {DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();// 关联realm.dwsm.setRealm(shiroRealm);//用户授权/认证信息Cache,采用EhCache缓存dwsm.setCacheManager(getEhCacheCache());dwsm.setSessionManager(getDefaultWebSessionManager());//注入记住我管理器;/*  dwsm.setRememberMeManager(rememberMeManager());*/return dwsm;}@Beanpublic ShiroRealm shiroRealm(EhCacheManager cacheManager) {ShiroRealm shiroRealm = new ShiroRealm();shiroRealm.setCacheManager(cacheManager);return shiroRealm;}//开启shiro注解支持@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(ShiroRealm shiroRealm){AuthorizationAttributeSourceAdvisor aasa =new AuthorizationAttributeSourceAdvisor();aasa.setSecurityManager(getDefaultWebSecurityManager(shiroRealm));return aasa;}/*** 配置前台页面thymeleaf页面的标签* @return*/@Beanpublic ShiroDialect shiroDialect() {return new ShiroDialect();}}

4.核心的授权认证类

import com.example.echart.entity.Permission;
import com.example.echart.entity.Role;
import com.example.echart.entity.User;
import com.example.echart.mapper.UserRoleMapper;
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.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** @ Author     :Zgq* @ Date       :Created in 18:19 2019/6/11* @ Description:Shiro中最主要的代码,核心代码,用户认证授权处* @ Modified By:* @Version: $*/
public class ShiroRealm extends AuthorizingRealm {@Autowiredprivate SessionDAO sessionDAO;@Autowiredprivate UserRoleMapper userRoleMapper;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection auth) {//授权String username = (String)auth.getPrimaryPrincipal();System.out.println("进入到授权Realm中:"+username);List<Role> dbroleList = userRoleMapper.selectRoleList(username);List<String> roleList=new ArrayList<String>();for(Role r:dbroleList){roleList.add(r.getCode());}List<Permission> dbpermissions = userRoleMapper.selectPermissionList(username);List<String> permissionList=new ArrayList<String>();for(Permission p:dbpermissions){permissionList.add(p.getPermission());}//        roleList.add("ADMIN");
//        roleList.add("USER");//        List<String> permissionList=new ArrayList<String>();
//        permissionList.add("ADMIN:USER:UPDATA");
//        permissionList.add("ADMIN:USER:DELETE");SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();simpleAuthorizationInfo.addRoles(roleList);simpleAuthorizationInfo.addStringPermissions(permissionList);return simpleAuthorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {//认证String username = (String)auth.getPrincipal();System.out.println("进入到认证Realm中:"+username);//在认证之前判断当前登录用户,只允许一个账号登录Collection<Session> sessions = sessionDAO.getActiveSessions();for (Session session : sessions){String loginedUsername = String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));if(username.equals(loginedUsername)){session.setTimeout(0);break;}}//通过username在数据库中查询用户,判断密码User dbuser = userRoleMapper.selectByUserName(username);//通过用户名在数据库中拿到,判断用户名和密码对不对if(dbuser!=null){SimpleAuthenticationInfo authInfo = new SimpleAuthenticationInfo(username, dbuser.getPwd(), "userRealm");return authInfo;}return null;}
}

5.登录的Controller类,LoginController

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;/*** @ Author     :Zgq* @ Date       :Created in 10:30 2019/6/12* @ Description:登录层方法* @ Modified By:* @Version: $*/@Controller
public class LoginController {//登录页面@RequestMapping(value = {"/login"})public String login(Map<String,String> map) {map.put("msg","请登录");return "/shiro/login-page";}//登录成功页面@RequestMapping(value = {"/index"})public String index(Map<String,String> map) {map.put("msg","登录成功");//获取用户信息Subject subject = SecurityUtils.getSubject();String username = (String)subject.getPrincipal();map.put("username",username);return "/shiro/index";}//登录请求@RequestMapping(value = {"/userLogin"})public String userLogin(String username, String pwd,boolean rememberMe, Map<String,String> map){Subject subject = SecurityUtils.getSubject();//根据自己盐加密的方式,放入密码String encodePwd = new Md5Hash(pwd, username).toString();UsernamePasswordToken auth = new UsernamePasswordToken(username, encodePwd,rememberMe);try {subject.login(auth);return "redirect:/index";}catch (Exception e){e.printStackTrace();map.put("msg","账号或密码错误");return "redirect:/login";}}//退出登录@RequestMapping(value = {"/loginOut"})public String loginOut(Map<String,String> map) {//获取用户信息Subject subject = SecurityUtils.getSubject();subject.logout();map.put("msg","退出登录");return "redirect:/login";}/*** 加密的测试* @param args*/public static void main(String[] args) {//加密String zhouguoqing = new Md5Hash("111", "admin1").toString();System.out.println(zhouguoqing);}
}

6.因为是和数据库直接对接的,所以我也新建了一个UserRoleMapper接口,返回数据

import com.example.echart.entity.Permission;
import com.example.echart.entity.Role;
import com.example.echart.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;import java.util.List;@Mapper
@Component
public interface UserRoleMapper {/*** 通过登录名查询信息* @param username* @return* @throws Exception*/@Select("select * from t_user where username=#{username} limit 1")User selectByUserName(String username);/*** 通过用户名查询用户角色信息* @param username* @return* @throws Exception*/@Select("select * from t_user u,t_role r,t_user_role ur where u.username=#{username} and ur.userId=u.id and ur.roleId=r.id")List<Role>  selectRoleList(String username);/*** 通过用户名查找用户权限* @param username* @return*/@Select("select * from t_permission p \n" +"where p.id in(\n" +"\tselect permissionId from t_role_permission rp \n" +"\twhere rp.roleId in (\n" +"\t\t\tselect ur.roleId from t_user_role ur where userId in(\n" +"\t\t\tselect u.id from t_user u where u.username=#{username}\n" +"\t\t\t)\n" +"\t)\n" +")")List<Permission> selectPermissionList(String username);}

7.前台页面thymeleaf的展示

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"xmlns:shiro="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><span th:text="${msg}"></span>
你好:<span th:text="${username}"></span><form action="/loginOut" method="post"><input type="submit" value="退出">
</form><p shiro:hasRole="ADMIN">ADMIN角色</p>
<p shiro:hasRole="USER">USER角色</p>
<p shiro:hasRole="SUPERMANE">SUPERMAN角色</p><p shiro:hasPermission="ADMIN:USER:UPDATA">UPDATA权限</p>
<p shiro:hasPermission="ADMIN:USER:DELETE">DELETE权限</p>
<p shiro:hasPermission="ADMIN:USER:INSERT">INSERT权限</p>
<p shiro:hasPermission="ADMIN:USER:SELECT">SELECT权限</p>
</body>
</html>

3.完成的效果


用不同用户登录之后会自动获取登录用户的角色和权限信息

学习地址:https://www.bilibili.com/video/av44084437

SpringBoot集成Shiro安全框架相关推荐

  1. springboot集成shiro实现用户登录认证

    Apache Shiro 是一个功能强大且易于使用的Java安全框架,可执行身份验证.授权.加密和会话管理.使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大 ...

  2. php 配置文件加密工具类,SpringBoot集成Jasypt安全框架以及配置文件内容加密(代码示例)...

    本篇文章给大家带来的内容是关于SpringBoot集成Jasypt安全框架以及配置文件内容加密(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 我们在SpringBoot项 ...

  3. springboot集成shiro 前后端分离 统一处理shiro异常

    springboot集成shiro 前后端分离 统一处理shiro异常 参考文章: (1)springboot集成shiro 前后端分离 统一处理shiro异常 (2)https://www.cnbl ...

  4. SpringBoot集成权限认证框架(Sa-Token)

    SpringBoot集成权限认证框架(Sa-Token) 介绍 身份验证又称"验证"."鉴权",是指通过一定的手段,完成对用户身份的确认. 身份验证的目的是确认 ...

  5. apache shiro jar包_只需要6个步骤,springboot集成shiro,并完成登录

    小Hub领读: 导入jar包,配置yml参数,编写ShiroConfig定义DefaultWebSecurityManager,重写Realm,编写controller,编写页面,一气呵成.搞定,是个 ...

  6. Springboot集成Shiro+Redis后,@Transactional注解不起作用

    为什么80%的码农都做不了架构师?>>>    使用Springboot构建 mybatis+Shiro+Redis+Druid 的前后端分离web项目, 具体可以参考博客https ...

  7. (课堂作业)spring-boot集成shiro的步骤及代码解析

    1.创建一个简单的Springboot项目,包含shiro和mybatis-plus. 2.集成shiro 2.1引入依赖 <dependency><groupId>org.a ...

  8. 【Springboot学习】SpringBoot集成Shiro前后端分离使用redis做缓存【个人博客搭建】

    shiro-redis 目录 shiro-redis 下载 shiro-core/jedis 版本对比图 使用前 如何配置? 设置文件 Redis 独立 Redis哨兵 Redis 集群 Spring ...

  9. Springboot 集成 Shiro 入门学习

    文章目录 Shiro概述 主要特征 shiro如何工作 官方快速开始代码分析 Springboot整合Shiro 导入依赖 创建配置类ShiroConfig 创建Realm 创建控制器 创建静态页面 ...

最新文章

  1. 技嘉主板bios设置键盘不能用_BIOS不再硬梆梆、全新技嘉主板BIOS设置就算不是玩家也能轻松搞定...
  2. js 对象深拷贝_这一次,彻底理解JavaScript深拷贝
  3. 用 vue 写小程序,基于 mpvue 框架重写 weui
  4. 905. 按奇偶排序数组
  5. 知乎超高赞:都有哪些习惯值得长期坚持?
  6. 两年Java工作经验应该会些什么技术
  7. 浏览器访问网页的详细内部过程
  8. 服务器主动发送fin信号,tcp 服务器向客户端发送FIN
  9. 智能优化算法:萤火虫算法-附代码
  10. selenium下载或保存图片最好的方法
  11. Adobe Premiere基础-常用的视频特效(裁剪,黑白,剪辑速度,镜像,镜头光晕)(十五)
  12. 阿里巴巴编码规范习题
  13. 组建团队和调整团队结构
  14. html编码器是什么意思,编码器是什么意思
  15. 微信预览wx.previewImage黑屏
  16. 怎么把知网下载的caj格式论文转成wrod格式呢
  17. java输出hello java_eclipse输出Hello World的实现方法
  18. 在线引流工具Tcpcopy原理、使用、采坑
  19. 熊猫的python小课_朋友圈里那个可爱的小熊猫Python编程的学习笔记,学编程,不难!...
  20. 联合概率数据互联(JPDA) ----多假设跟踪(MHT)

热门文章

  1. easyui confirm使用方法
  2. 惠普笔记本电脑星(14/15)系列拆机历险记
  3. CHDOJ——P2124采购礼品
  4. 保留thinkvantage一键恢复功能的Linux与vista双系统安装
  5. Android布局初学习
  6. 基于表单的暴力破解演示
  7. asp.net MVC之AuthorizeAttribute浅析
  8. CCNA实验三 把路由器配置成PC
  9. Python语言基础 (第一节)
  10. Promise 用法