Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架

作者 : admin 本文共17326个字,预计阅读时间需要44分钟 发布时间: 2021-12-5 共6人阅读

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架

项目背景

公司在几年前就采用了前后端分离的开发模式,前端所有请求都使用ajax。这样的项目结构在与CAS单点登录等权限管理框架集成时遇到了很多问题,使得权限部分的代码冗长丑陋,CAS的各种重定向也使得用户体验很差,在前端使用vue-router管理页面跳转时,问题更加尖锐。于是我就在寻找一个解决方案,这个方案应该对代码的侵入较少,开发速度快,实现优雅。最近无意中看到springboot与shiro框架集成的文章,在了解了springboot以及shiro的发展状况,并学习了使用方法后,开始在网上搜索前后端分离模式下这两个框架的适应性,在经过测试后发现可行,完全符合个人预期。

解决方案

本文中项目核心包为SpringBoot1.5.9.RELEASE以及shiro-spring 1.4.0,为了加快开发效率,持久化框架使用hibernate-JPA,为增加可靠性,sessionId的管理使用了shiro-redis开源插件,避免sessionId断电丢失,同时使得多端可共享session,项目结构为多模块项目,详见下图。

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架插图

 

其中spring-boot-shiro模块为本文重点,该模块包含shiro核心配置,shiro数据源配置以及各种自定义实现,登录相关服务等。该模块在项目中使用时可直接在pom中引用,并在spring-boot-main入口模块中配置相应数据库连接信息即可,且该模块可以在多个项目中复用,避免重复开发。spring-boot-module1为模拟真实项目中的业务模块,可能会有多个。spring-boot-common中包含通用工具类,常量,异常等等。多模块项目的搭建在本文中不作赘述。

母模块pom.xml代码如下

 

  1. <?xml version=”1.0″ encoding=”UTF-8″?>
  2. <project xmlns=“http://maven.apache.org/POM/4.0.0”
  3. xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
  4. xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.xxx</groupId>
  7. <artifactId>spring-boot-parent</artifactId>
  8. <packaging>pom</packaging>
  9. <version>1.0-SNAPSHOT</version>
  10. <modules>
  11. <module>spring-boot-main</module>
  12. <module>spring-boot-module1</module>
  13. <module>spring-boot-shiro</module>
  14. <module>spring-boot-common</module>
  15. </modules>
  16. <properties>
  17. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  19. <java.version>1.8</java.version>
  20. <spring-boot.version>1.5.9.RELEASE</spring-boot.version>
  21. <shiro.version>1.4.0</shiro.version>
  22. </properties>
  23. <dependencies>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-web</artifactId>
  27. <version>${spring-boot.version}</version>
  28. </dependency>
  29. <!–在外部tomcat中发布故移除内置包–>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-tomcat</artifactId>
  33. <version>${spring-boot.version}</version>
  34. <scope>provided</scope>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-test</artifactId>
  39. <version>${spring-boot.version}</version>
  40. <scope>test</scope>
  41. </dependency>
  42. <dependency>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-devtools</artifactId>
  45. <version>${spring-boot.version}</version>
  46. <optional>true</optional>
  47. </dependency>
  48. <dependency>
  49. <groupId>org.springframework.boot</groupId>
  50. <artifactId>spring-boot-starter-data-jpa</artifactId>
  51. <version>${spring-boot.version}</version>
  52. </dependency>
  53. <dependency>
  54. <groupId>org.apache.shiro</groupId>
  55. <artifactId>shiro-spring</artifactId>
  56. <version>${shiro.version}</version>
  57. </dependency>
  58. <dependency>
  59. <groupId>com.alibaba</groupId>
  60. <artifactId>fastjson</artifactId>
  61. <version>1.2.8</version>
  62. </dependency>
  63. <dependency>
  64. <groupId>com.alibaba</groupId>
  65. <artifactId>druid</artifactId>
  66. <version>1.0.28</version>
  67. </dependency>
  68. <dependency>
  69. <groupId>mysql</groupId>
  70. <artifactId>mysql-connector-java</artifactId>
  71. <version>5.1.39</version>
  72. <scope>runtime</scope>
  73. </dependency>
  74. <!–<dependency>–>
  75. <!–<groupId>org.springframework.boot</groupId>–>
  76. <!–<artifactId>spring-boot-starter-thymeleaf</artifactId>–>
  77. <!–<version>${spring-boot.version}</version>–>
  78. <!–</dependency>–>
  79. <!–<dependency>–>
  80. <!–<groupId>net.sourceforge.nekohtml</groupId>–>
  81. <!–<artifactId>nekohtml</artifactId>–>
  82. <!–<version>1.9.22</version>–>
  83. <!–</dependency>–>
  84. </dependencies>
  85. </project>

 

spring-boot-shiro模块接口如下图

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架插图(1)

传统结构项目中,shiro从cookie中读取sessionId以此来维持会话,在前后端分离的项目中(也可在移动APP项目使用),我们选择在ajax的请求头中传递sessionId,因此需要重写shiro获取sessionId的方式。自定义MySessionManager类继承DefaultWebSessionManager类,重写getSessionId方法,代码如下

 

  1. import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
  2. import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
  3. import org.apache.shiro.web.util.WebUtils;
  4. import org.springframework.util.StringUtils;
  5. import javax.servlet.ServletRequest;
  6. import javax.servlet.ServletResponse;
  7. import java.io.Serializable;
  8. /**
  9. * Created by Administrator on 2017/12/11.
  10. * 自定义sessionId获取
  11. */
  12. public class MySessionManager extends DefaultWebSessionManager {
  13. private static final String AUTHORIZATION = “Authorization”;
  14. private static final String REFERENCED_SESSION_ID_SOURCE = “Stateless request”;
  15. public MySessionManager() {
  16. super();
  17. }
  18. @Override
  19. protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
  20. String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
  21. //如果请求头中有 Authorization 则其值为sessionId
  22. if (!StringUtils.isEmpty(id)) {
  23. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
  24. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
  25. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
  26. return id;
  27. } else {
  28. //否则按默认规则从cookie取sessionId
  29. return super.getSessionId(request, response);
  30. }
  31. }
  32. }

 

 

 

如何配置让shiro执行我们的自定义sessionManager呢?下面看ShiroConfig类。

 

  1. package com.xxx.shiro.config;
  2. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  3. import org.apache.shiro.mgt.SecurityManager;
  4. import org.apache.shiro.session.mgt.SessionManager;
  5. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  6. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  7. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  8. import org.crazycake.shiro.RedisCacheManager;
  9. import org.crazycake.shiro.RedisManager;
  10. import org.crazycake.shiro.RedisSessionDAO;
  11. import org.springframework.beans.factory.annotation.Value;
  12. import org.springframework.context.annotation.Bean;
  13. import org.springframework.context.annotation.Configuration;
  14. import org.springframework.web.servlet.HandlerExceptionResolver;
  15. import java.util.LinkedHashMap;
  16. import java.util.Map;
  17. /**
  18. * Created by Administrator on 2017/12/11.
  19. */
  20. @Configuration
  21. public class ShiroConfig {
  22. @Value(“${spring.redis.shiro.host}”)
  23. private String host;
  24. @Value(“${spring.redis.shiro.port}”)
  25. private int port;
  26. @Value(“${spring.redis.shiro.timeout}”)
  27. private int timeout;
  28. @Value(“${spring.redis.shiro.password}”)
  29. private String password;
  30. @Bean
  31. public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
  32. System.out.println(“ShiroConfiguration.shirFilter()”);
  33. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  34. shiroFilterFactoryBean.setSecurityManager(securityManager);
  35. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
  36. //注意过滤器配置顺序 不能颠倒
  37. //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
  38. filterChainDefinitionMap.put(“/logout”, “logout”);
  39. // 配置不会被拦截的链接 顺序判断
  40. filterChainDefinitionMap.put(“/static/**”, “anon”);
  41. filterChainDefinitionMap.put(“/ajaxLogin”, “anon”);
  42. filterChainDefinitionMap.put(“/login”, “anon”);
  43. filterChainDefinitionMap.put(“/**”, “authc”);
  44. //配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
  45. shiroFilterFactoryBean.setLoginUrl(“/unauth”);
  46. // 登录成功后要跳转的链接
  47. // shiroFilterFactoryBean.setSuccessUrl(“/index”);
  48. //未授权界面;
  49. // shiroFilterFactoryBean.setUnauthorizedUrl(“/403”);
  50. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  51. return shiroFilterFactoryBean;
  52. }
  53. /**
  54. * 凭证匹配器
  55. * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
  56. * )
  57. *
  58. * @return
  59. */
  60. @Bean
  61. public HashedCredentialsMatcher hashedCredentialsMatcher() {
  62. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
  63. hashedCredentialsMatcher.setHashAlgorithmName(“md5”);//散列算法:这里使用MD5算法;
  64. hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(“”));
  65. return hashedCredentialsMatcher;
  66. }
  67. @Bean
  68. public MyShiroRealm myShiroRealm() {
  69. MyShiroRealm myShiroRealm = new MyShiroRealm();
  70. myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
  71. return myShiroRealm;
  72. }
  73. @Bean
  74. public SecurityManager securityManager() {
  75. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  76. securityManager.setRealm(myShiroRealm());
  77. // 自定义session管理 使用redis
  78. securityManager.setSessionManager(sessionManager());
  79. // 自定义缓存实现 使用redis
  80. securityManager.setCacheManager(cacheManager());
  81. return securityManager;
  82. }
  83. //自定义sessionManager
  84. @Bean
  85. public SessionManager sessionManager() {
  86. MySessionManager mySessionManager = new MySessionManager();
  87. mySessionManager.setSessionDAO(redisSessionDAO());
  88. return mySessionManager;
  89. }
  90. /**
  91. * 配置shiro redisManager
  92. * <p>
  93. * 使用的是shiro-redis开源插件
  94. *
  95. * @return
  96. */
  97. public RedisManager redisManager() {
  98. RedisManager redisManager = new RedisManager();
  99. redisManager.setHost(host);
  100. redisManager.setPort(port);
  101. redisManager.setExpire(1800);// 配置缓存过期时间
  102. redisManager.setTimeout(timeout);
  103. redisManager.setPassword(password);
  104. return redisManager;
  105. }
  106. /**
  107. * cacheManager 缓存 redis实现
  108. * <p>
  109. * 使用的是shiro-redis开源插件
  110. *
  111. * @return
  112. */
  113. @Bean
  114. public RedisCacheManager cacheManager() {
  115. RedisCacheManager redisCacheManager = new RedisCacheManager();
  116. redisCacheManager.setRedisManager(redisManager());
  117. return redisCacheManager;
  118. }
  119. /**
  120. * RedisSessionDAO shiro sessionDao层的实现 通过redis
  121. * <p>
  122. * 使用的是shiro-redis开源插件
  123. */
  124. @Bean
  125. public RedisSessionDAO redisSessionDAO() {
  126. RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
  127. redisSessionDAO.setRedisManager(redisManager());
  128. return redisSessionDAO;
  129. }
  130. /**
  131. * 开启shiro aop注解支持.
  132. * 使用代理方式;所以需要开启代码支持;
  133. *
  134. * @param securityManager
  135. * @return
  136. */
  137. @Bean
  138. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
  139. AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  140. authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  141. return authorizationAttributeSourceAdvisor;
  142. }
  143. /**
  144. * 注册全局异常处理
  145. * @return
  146. */
  147. @Bean(name = “exceptionHandler”)
  148. public HandlerExceptionResolver handlerExceptionResolver() {
  149. return new MyExceptionHandler();
  150. }
  151. }

 

 

 

在定义的SessionManager的Bean中返回我们的MySessionManager,然后在SecurityManager的Bean中调用setSessionManager(SessionManager sessionManager)方法加载我们的自定义SessionManager。

附上
MyShiroRealm的代码

 

  1. package com.xxx.shiro.config;
  2. import com.xxx.shiro.entity.SysPermission;
  3. import com.xxx.shiro.entity.SysRole;
  4. import com.xxx.shiro.entity.UserInfo;
  5. import com.xxx.shiro.service.UserInfoService;
  6. import org.apache.shiro.authc.*;
  7. import org.apache.shiro.authz.AuthorizationInfo;
  8. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  9. import org.apache.shiro.realm.AuthorizingRealm;
  10. import org.apache.shiro.subject.PrincipalCollection;
  11. import org.apache.shiro.util.ByteSource;
  12. import javax.annotation.Resource;
  13. /**
  14. * Created by Administrator on 2017/12/11.
  15. * 自定义权限匹配和账号密码匹配
  16. */
  17. public class MyShiroRealm extends AuthorizingRealm {
  18. @Resource
  19. private UserInfoService userInfoService;
  20. @Override
  21. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  22. // System.out.println(“权限配置–>MyShiroRealm.doGetAuthorizationInfo()”);
  23. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  24. UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();
  25. for (SysRole role : userInfo.getRoleList()) {
  26. authorizationInfo.addRole(role.getRole());
  27. for (SysPermission p : role.getPermissions()) {
  28. authorizationInfo.addStringPermission(p.getPermission());
  29. }
  30. }
  31. return authorizationInfo;
  32. }
  33. /*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
  34. @Override
  35. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
  36. throws AuthenticationException {
  37. // System.out.println(“MyShiroRealm.doGetAuthenticationInfo()”);
  38. //获取用户的输入的账号.
  39. String username = (String) token.getPrincipal();
  40. // System.out.println(token.getCredentials());
  41. //通过username从数据库中查找 User对象,如果找到,没找到.
  42. //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
  43. UserInfo userInfo = userInfoService.findByUsername(username);
  44. // System.out.println(“—–>>userInfo=”+userInfo);
  45. if (userInfo == null) {
  46. return null;
  47. }
  48. if (userInfo.getState() == 1) { //账户冻结
  49. throw new LockedAccountException();
  50. }
  51. SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
  52. userInfo, //用户名
  53. userInfo.getPassword(), //密码
  54. ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt
  55. getName() //realm name
  56. );
  57. return authenticationInfo;
  58. }
  59. }

 

 

 

传统项目中,登录成功后应该重定向请求,但在前后端分离项目中,通过ajax登录后应该返回登录状态标志以及相关信息。Web层登录方法代码如下

 

  1. /**
  2. * 登录方法
  3. * @param userInfo
  4. * @return
  5. */
  6. @RequestMapping(value = “/ajaxLogin”, method = RequestMethod.POST)
  7. @ResponseBody
  8. public String ajaxLogin(UserInfo userInfo) {
  9. JSONObject jsonObject = new JSONObject();
  10. Subject subject = SecurityUtils.getSubject();
  11. UsernamePasswordToken token = new UsernamePasswordToken(userInfo.getUsername(), userInfo.getPassword());
  12. try {
  13. subject.login(token);
  14. jsonObject.put(“token”, subject.getSession().getId());
  15. jsonObject.put(“msg”, “登录成功”);
  16. } catch (IncorrectCredentialsException e) {
  17. jsonObject.put(“msg”, “密码错误”);
  18. } catch (LockedAccountException e) {
  19. jsonObject.put(“msg”, “登录失败,该用户已被冻结”);
  20. } catch (AuthenticationException e) {
  21. jsonObject.put(“msg”, “该用户不存在”);
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. return jsonObject.toString();
  26. }

 

 

 

本项目使用SpringMVC框架,可以自行修改使用其他MVC框架。登录成功则返回sessionId作为token给前端存储,前端请求时将该token放入请求头,以Authorization为key,以此来鉴权。如果出现账号或密码错误等异常则返回错误信息。

传统项目中,登出后应重定向请求,到登录界面或其他指定界面,在前后端分离的项目中,我们应该返回json信息。在上面提到的ShiroConfig中配置了默认登录路由

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架插图(2)

在Web层加入方法

 

  1. /**
  2. * 未登录,shiro应重定向到登录界面,此处返回未登录状态信息由前端控制跳转页面
  3. * @return
  4. */
  5. @RequestMapping(value = “/unauth”)
  6. @ResponseBody
  7. public Object unauth() {
  8. Map<String, Object> map = new HashMap<String, Object>();
  9. map.put(“code”, “1000000”);
  10. map.put(“msg”, “未登录”);
  11. return map;
  12. }

 

 

 

此处简单提示未登录返回状态码,也可自行定义信息。

在项目中,权限相关表可能不在业务库中,因此有必要单独配置权限相关表的数据源。详细配置可以参见《Spring Boot多数据源配置与使用》一文。

Shiro数据源配置代码

 

  1. package com.xxx.shiro.datasource;
  2. import java.util.Map;
  3. import javax.persistence.EntityManager;
  4. import javax.sql.DataSource;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.beans.factory.annotation.Qualifier;
  7. import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
  8. import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  12. import org.springframework.orm.jpa.JpaTransactionManager;
  13. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
  14. import org.springframework.transaction.PlatformTransactionManager;
  15. import org.springframework.transaction.annotation.EnableTransactionManagement;
  16. /**
  17. * Created by Administrator on 2017/12/11.
  18. */
  19. @Configuration
  20. @EnableTransactionManagement
  21. @EnableJpaRepositories(
  22. entityManagerFactoryRef=”shiroEntityManagerFactory”,
  23. transactionManagerRef=”shiroTransactionManager”,
  24. basePackages= { “com.xxx.shiro.dao” })
  25. public class ShiroDataSourceConfig {
  26. @Autowired
  27. private JpaProperties jpaProperties;
  28. @Autowired
  29. @Qualifier(“shiroDataSource”)
  30. private DataSource shiroDataSource;
  31. @Bean(name = “shiroEntityManager”)
  32. public EntityManager shiroEntityManager(EntityManagerFactoryBuilder builder) {
  33. return shiroEntityManagerFactory(builder).getObject().createEntityManager();
  34. }
  35. @Bean(name = “shiroEntityManagerFactory”)
  36. public LocalContainerEntityManagerFactoryBean shiroEntityManagerFactory (EntityManagerFactoryBuilder builder) {
  37. return builder
  38. .dataSource(shiroDataSource)
  39. .properties(getVendorProperties(shiroDataSource))
  40. .packages(“com.xxx.shiro.entity”)
  41. .persistenceUnit(“shiroPersistenceUnit”)
  42. .build();
  43. }
  44. private Map<String, String> getVendorProperties(DataSource dataSource) {
  45. return jpaProperties.getHibernateProperties(dataSource);
  46. }
  47. @Bean(name = “shiroTransactionManager”)
  48. PlatformTransactionManager shiroTransactionManager(EntityManagerFactoryBuilder builder) {
  49. return new JpaTransactionManager(shiroEntityManagerFactory(builder).getObject());
  50. }
  51. }

 

IDEA下JpaProperties可能会报错,可以忽略。

入口模块结构如下图

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架插图(3)

 

DataSourceConfig中配置了多个数据源的Bean,其中shiro数据源Bean代码

 

  1. /**
  2. * shiro数据源
  3. * @return
  4. */
  5. @Bean(name = “shiroDataSource”)
  6. @Qualifier(“shiroDataSource”)
  7. @ConfigurationProperties(prefix=”spring.datasource.shiro”)
  8. public DataSource shiroDataSource() {
  9. return DataSourceBuilder.create().build();
  10. }

 

 

 

ServletInitializer和StartApp为SpringBoot在外部tomcat启动配置,不赘述。

SpringBoot的相关配置在application.yml中,shiro配置代码如下图

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架插图(4)

Primary为主库配置。当在某个项目中引入spring-boot-shiro模块时,只需要在配置文件中加入shiro数据源及redis的相关配置,并在DataSourceConfig加入shiro数据源Bean即可。

Shiro框架会根据用户登录及权限状态抛出异常,建议使用SpringMVC的全局异常捕获来处理异常,避免重复代码。该项目中代码如下

  1. package com.xxx.shiro.config;
  2. import com.alibaba.fastjson.support.spring.FastJsonJsonView;
  3. import org.apache.shiro.authz.UnauthenticatedException;
  4. import org.apache.shiro.authz.UnauthorizedException;
  5. import org.springframework.web.servlet.HandlerExceptionResolver;
  6. import org.springframework.web.servlet.ModelAndView;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. /**
  12. * Created by Administrator on 2017/12/11.
  13. * 全局异常处理
  14. */
  15. public class MyExceptionHandler implements HandlerExceptionResolver {
  16. public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
  17. ModelAndView mv = new ModelAndView();
  18. FastJsonJsonView view = new FastJsonJsonView();
  19. Map<String, Object> attributes = new HashMap<String, Object>();
  20. if (ex instanceof UnauthenticatedException) {
  21. attributes.put(“code”, “1000001”);
  22. attributes.put(“msg”, “token错误”);
  23. } else if (ex instanceof UnauthorizedException) {
  24. attributes.put(“code”, “1000002”);
  25. attributes.put(“msg”, “用户无权限”);
  26. } else {
  27. attributes.put(“code”, “1000003”);
  28. attributes.put(“msg”, ex.getMessage());
  29. }
  30. view.setAttributesMap(attributes);
  31. mv.setView(view);
  32. return mv;
  33. }
  34. }

 

该Bean在ShiroConfig中已有注册代码。

 

至此,shiro框架的集成就结束了。至于shiro框架的使用细节,可以自行查阅相关资料。项目代码本人测试可正常工作,未应用到生产环境,仅供学习交流使用。

参考文章

1.  《在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制

 

2.  《Spring Boot多数据源配置与使用

 

3.  《springboot整合shiro-登录认证和权限管理

 

需要源码的朋友可以看看我的另一篇博文《SpringBoot+Shiro+MyBatisPlus搭建前后端分离的多模块项目

更优雅的源代码,更新的springboot版本,热点问题解答,可以看看最新博文《SpringBoot2.0,Thymeleaf与Shiro整合

Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架


滴石it网-Java学习中高级和架构师教程_Java企业级开发项目实战下载 » Spring Boot整合Shiro 权限管理 在前后端分离的SpringBoot项目中集成Shiro权限框架

常见问题FAQ

发表评论

开通VIP 享更多特权,建议使用QQ登录