官网:https://shiro.apache.org/

1. 下载
在Maven项目中的依赖配置如下:

<!-- shiro配置 -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${version.shiro}</version>
</dependency>
<!-- Enables support for web-based applications. -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${version.shiro}</version>
</dependency>
<!-- Enables AspectJ support for Shiro AOP and Annotations. -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-aspectj</artifactId>
<version>${version.shiro}</version>
</dependency>
<!-- Enables Ehcache-based famework caching. -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${version.shiro}</version>
</dependency>
<!-- Enables Spring Framework integration. -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${version.shiro}</version>
</dependency>

特别地!Shiro使用了日志框架slf4j,因此需要对应配置指定的日志实现组件,如:log4j,logback等。
在此,以使用log4j为日志实现为例:

<!-- 日志工具 -->
<!--
shiro使用slf4j作为日志框架,所以必需配置slf4j。
同时,使用log4j作为底层的日志实现框架。
-->
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.25</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.25</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>

2.集成Shiro
在Spring框架中集成Shiro,本质上是与Spring IoC容器和Spring MVC框架集成,所以应该分为2部分来说。
(1)与Spring IoC容器集成
Spring IoC容器提供了一个非常重要的功能,就是依赖注入,将Bean的定义以及Bean之间关系的耦合通过容器来处理。
也就是说,在Spring中集成Shiro时,Shiro中的相应Bean的定义以及他们的关系也需要通过Spring IoC容器实现,配置如下:

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/index"/>
<property name="successUrl" value="/home"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean -->
<!-- defined will be automatically acquired and available via its beanName in chain -->
<!-- definitions, but you can perform instance overrides or name aliases here if you like: -->
<!-- <property name="filters">
<util:map>
<entry key="logout" value-ref="logoutFilter" />
</util:map>
</property> -->
<property name="filterChainDefinitions">
<value>
# some example chain definitions:
# /admin/** = authc, roles[admin]
# /docs/** = authc, perms[document:read]
/login = anon
/logout = anon
/error = anon
/** = user
# more URL-to-FilterChain definitions here
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="myRealm" />
<!-- By default the servlet container sessions will be used. Uncomment this line
to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- Define the Shiro Realm implementation you want to use to connect to your back-end -->
<!-- security datasource: -->
<bean id="myRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource"/>
<property name="permissionsLookupEnabled" value="true"/>
</bean> <!-- Enable Shiro Annotations for Spring-configured beans. Only run after -->
<!-- the lifecycleBeanProcessor has run: -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>

(2)与Spring MVC集成

跟在普通Java Web应用中使用Shiro一样,集成Shiro到Spring MVC时,实际上就是通过在web.xml中添加指定Filter实现。配置如下:

<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter> <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all -->
<!-- requests. Usually this filter mapping is defined first (before all others) to -->
<!-- ensure that Shiro works in subsequent filters in the filter chain: -->
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

也就是说,其实在Spring中集成Shiro的原理就是:通过在web.xml中配置的Shiro Filter与Spring IoC中定义的相应的Shiro Bean定义建立关系,从而实现在Spring框架集成Shiro。
实际上,通常就是在web.xml添加的Filter与某个Shiro Spring Bean的定义name是相同的,参见示例。
Shiro Filter类图:

3. 数据源配置
在Shiro中,Realm定义了访问数据的方式,用来连接不同的数据源,如:LDAP,关系数据库,配置文件等等。
Realm类图:

也就是说,可以根据实际需求及应用的权限管理复杂度灵活选择指定数据源。
在此,以org.apache.shiro.realm.jdbc.JdbcRealm为例,将用户信息存放在关系型数据库中。

在使用org.apache.shiro.realm.jdbc.JdbcRealm时,必须要在关系型数据库中存在3张表,分别是:
(1)users表,存放认证用户基本信息,在该表中必须存在2个字段:username,password。
(2)roles_permissions表,存放角色和权限定义,在该表中必须存在2个字段:role_name,permission。
(3)user_roles表,存放用户角色对应关系,在该表中必须存在2个字段:username,role_name。
实际上,在更加复杂的应用场景下,通常需要扩展org.apache.shiro.realm.jdbc.JdbcRealm。

4. 认证
在Shiro中,认证即执行用户登录,读取指定Realm连接的数据源,以验证用户身份的有效性与合法性。
关于Shiro在Web应用中的认证流程,与Shiro在非Web环境的独立应用中的认证流程一样,都需要执行用户登录,即:

Subject currentUser = SecurityUtils.getSubject();
if(!currentUser.isAuthenticated()) {
  UsernamePasswordToken token = new UsernamePasswordToken(name, password);
  try {
    currentUser.login(token);
  } catch (UnknownAccountException e) {
    logger.error(String.format("user not found: %s", name), e);
  } catch(IncorrectCredentialsException e) {
    logger.error(String.format("user: %s pwd: %s error", name, password), e);
  } catch (ConcurrentAccessException e) {
    logger.error(String.format("user has been authenticated: %s", name), e);
  } catch (AuthenticationException e) {
    logger.error(String.format("account except: %s", name), e);
  }
}

唯一的区别就是,在Java Web环境中,用户名和密码参数是通过前端页面进行传递。

5. 授权
需要再三强调!!!Shiro作为权限框架,仅仅只能控制对资源的操作权限,并不能完成对数据权限的业务需求。
而对于Java Web环境下Shiro授权,包含个方面的含义。
其一,对于前端来说,用户只能看到他对应访问权限的元素。
其二,当用户执行指定操作(即:访问某个uri资源)时,需要验证用户是否具备对应权限。
对于第一点,在Java Web环境下,通过Shiro提供的JSP标签实现。

<shiro:hasRole name="admin">
  <a>用户管理</a>
</shiro:hasRole>
<shiro:hasPermission name="winnebago:drive:eagle5">
  <a>操作审计</a>
</shiro:hasPermission>

必须在jsp页面中引入shiro标签库:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

对于第二点,与在非Java Web环境下一样,需要在后端调用API进行权限(或者角色)检验。
api调用:

String roleAdmin = "admin";
Subject currentUser = SecurityUtils.getSubject();
if(!currentUser.hasRole(roleAdmin)) {
  //todo something
}

在Spring框架中集成Shiro,还可以直接通过Java注解方式实现:

@Controller
public class HomeController {
  @RequestMapping("/home")
  @RequiresPermissions(value={"log:manage:*"})
  public ModelAndView home(HttpServletRequest req) {
    ModelAndView mv = new ModelAndView("home");
    return mv;
  }
}

6.Spring集成Shiro注意事项

假设存在如下几个配置文件,分别是:
springDAO.xml:数据源定义
springMVC.xml:Spring MVC配置
springService.xml:其他Spring组件配置
springShiro.xml:Shiro相关Bean配置

第一,在不同版本的Spring中集成Shiro,实现方式不同。
(1)在Spring 4.2.0 RELEASE+版本中集成Shiro:
web.xml:

<servlet>
  <servlet-name>SpringMVC</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/spring*.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>SpringMVC</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

(2)在Spring 4.1.9 RELEASE-版本中集成Shiro:
web.xml:

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/springDAO.xml,classpath:/springService.xml,classpath:/springShiro.xml</param-value>
</context-param>
<servlet>
  <servlet-name>SpringMVC</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/springMVC.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>SpringMVC</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

同时,还需要将在springShiro.xml中配置的org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator放到springMVC.xml中,即:

<!-- 解决在spring 4.1.9 RELEASE及以下版本,集成shiro时注解不生效的问题 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>

第二,虽然shiro的注解定义是在Class级别的,但是实际验证只能支持方法级别:
@RequiresAuthentication
@RequiresPermissions
@RequiresRoles

7. 完整示例
详见:https://git.oschina.net/cchanghui/test-shirospring.git

细说shiro之五:在spring框架中集成shiro的更多相关文章

  1. Spring Boot 中集成 Shiro

    https://blog.csdn.net/taojin12/article/details/88343990

  2. 在前后端分离的SpringBoot项目中集成Shiro权限框架

    参考[1].在前后端分离的SpringBoot项目中集成Shiro权限框架 参考[2]. Springboot + Vue + shiro 实现前后端分离.权限控制   以及跨域的问题也有涉及

  3. 再析在spring框架中解决多数据源的问题

    在前面我写了<如何在spring框架中解决多数据源的问题>,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注.在与网友探讨该问题的过程中, ...

  4. Spring框架中 配置c3p0连接池 完成对数据库的访问

    开发准备: 1.导入jar包: ioc基本jar jdbcTemplate基本jar c3p0基本jar 别忘了mysql数据库驱动jar 原始程序代码:不使用配置文件方式(IOC)生成访问数据库对象 ...

  5. Spring框架中ModelAndView、Model、ModelMap区别

    原文地址:http://www.cnblogs.com/google4y/p/3421017.html SPRING框架中ModelAndView.Model.ModelMap区别   注意:如果方法 ...

  6. Spring框架中的定时器 使用和配置

    Spring框架中的定时器 如何使用和配置 转载自:<Spring框架中的定时器 如何使用和配置>https://www.cnblogs.com/longqingyang/p/554543 ...

  7. 【Spring】8、Spring框架中的单例Beans是线程安全的么

    看到这样一个问题:spring框架中的单例Beans是线程安全的么? Spring框架并没有对单例bean进行任何多线程的封装处理.关于单例bean的线程安全和并发问题需要开发者自行去搞定.但实际上, ...

  8. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

  9. Spring框架中IoC(控制反转)的原理(转)

    原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...

随机推荐

  1. 反射中Class.forName()和classLoader的区别

    搞清楚两者之间区别前,我们来了解下类加载过程. 一.类加载过程 1.加载 通过一个类的全限定名来获取定义此类的二进制字节流. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构. 在内存中生 ...

  2. linux rpm安装 failed depenencie(失败的依赖关系)错误原因

    rpm安装nfs 出现failed depenencie 经查资料得知命令后加上--nodeps --force,就可以了 加上那两个参数的意义就在于,安装时不再分析包之间的依赖关系而直接安装,也就不 ...

  3. 「FJOI2016」神秘数 解题报告

    「FJOI2016」神秘数 这题不sb,我挺sb的... 我连不带区间的都不会哇 考虑给你一个整数集,如何求这个神秘数 这有点像一个01背包,复杂度和值域有关.但是你发现01背包可以求出更多的东西,就 ...

  4. angular2路由与express路由冲突的问题

    angular2的路由定义了一个/a,如果走angular的路由没问题,如果直接访问/a就会出现cannot GET /a的错误,原因就是express的路由问题. 所以路由走angular2,那ex ...

  5. javascript之复习(css属性值的计算)

    js取div的宽高咋办,css有content-box,border-box,padding-box,表现又不一样.好在有个offsetWidth, <style type="text ...

  6. 洛谷P1848 书架

    好,我一直以为书架是splay,然后发现还有个优化DP的书架.妃的书架 蓝书和PPT上面都讲了,应该比较经典吧. 题意: 有n个物品,每个都有宽,高. 把它们分成若干段,使得每段的最大值的总和最小.且 ...

  7. Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(1)

    1.开发环境配置 Windows7 64位旗舰版 python3.6 node.js mysql navicat pycharm webstorm或vscode 2.项目初始化 新版的pycharm很 ...

  8. Linux系统调用之内存管理

    brk 改变数据段空间的分配 sbrk 参见brk mlock 内存页面加锁 munlock 内存页面解锁 mlockall 调用进程所有内存页面加锁 munlockall 调用进程所有内存页面解锁 ...

  9. java 文件创建 调试

    BufferedWriter bw=new BufferedWriter(new FileWriter("/2.txt")); bw.write("hello" ...

  10. ZOJ 1532 Internship (Dinic)

    看来模板又错了,敲你妈妈小饼干 #include<iostream> #include<queue> #include<cstring> #include<c ...