JAVA框架11 -- Shiro权限系统

权限系统设计概述

概述

权限系统实际上就是判断访问用户的合法性,有效性以及对访问资源权限的检查。

权限系统要素

  • 资源:授权访问。
  • 角色:访问资源的证书,定义了资源访问的界限,作为一个粗粒度的资源访问权限控制。
  • 主体:访问资源的对象,通常为登录用户。
  • 权限:访问资源的具体限定,权限可以细分为操作权限和数据权限。
    • 操作权限:体现在2个方面,其一:通过界面来体现,具备操作权限的人才可以在界面上看到对应资源;其二:访问指定资源时进行权限检查。
    • 数据权限:主体只能看到/操作他具备访问权限的资源,数据权限的设计可以通过数据库字段管关联来实现。

另外,可以根据权限系统设计的复杂性来决定权限控制粒度。可以将权限独立出来和角色进行组合,理解为通过角色和权限双重身份来限定主体授权访问资源;也可以将权限与角色关联,通过角色来定义主体/分组的权限。

  • 分组:通常对应于现实事物中的部门,主体属于分组,为分组定义角色。

常用权限框架

  • shiro
    JAVA实现的开源通用权限框架,不与特定框架进行绑定。功能全面,使用非常灵活。

  • Spring Security
    Java实现开源权限框架,与Spring框架绑定。功能强大,但是只能在Spring框架中使用。

shiro简介

官网

Shiro是什么

Shiro是一个Java平台的开源权限框架,用于认证和访问授权。具体来说,满足对如下元素的支持:

  • 用户,角色,权限(仅仅是操作权限,数据权限必须与业务需求紧密结合),资源(url)。
  • 用户分配角色,角色定义权限。
  • 访问授权时支持角色或者权限,并且支持多级的权限定义。

对组的支持?

  • shiro默认不支持对组设置权限。

是否可以满足对组进行角色分配的需求?

  • 扩展Realm,可以支持对组进行分配角色,其实就是给该组下的所有用户分配权限。

对数据权限的支持? 在业务系统中定义?

  • shiro仅仅实现对操作权限的控制,用于在前端控制元素隐藏或者显示,以及对资源访问权限进行检查。数据权限与具体的业务需求紧密关联,shiro本身无法实现对数据权限的控制。

动态权限分配?

  • 扩展org.apache.shiro.realm.Realm,支持动态权限分配。

与Spring集成?

  • 可以支持与Spring集成,shiro还支持jsp标签。

系统架构

在shiro架构中,有3个最主要的组件:Subject,SecurityManager,Realm。

  • Subject本质上就是当前访问用户的抽象描述。
  • SecurityManager是Shiro架构中最核心的组件,通过它可以协调其他组件完成用户认证和授权。实际上,SecurityManager就是Shiro框架的控制器。
  • Realm定义了访问数据的方式,用来连接不同的数据源,如:LDAP,关系数据库,配置文件等等。

Shiro原理

认证

  • 通过调用Subject.login(token)方法开始用户认证流程。
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
try {
  currentUser.login(token);
} catch (UnknownAccountException e) {
  logger.error(String.format("user not found: %s", username), e); // 用户不存在
} catch (IncorrectCredentialsException e) {
  logger.error(String.format("incorrent credentials: %s", username), e); // 密码不正确
} catch (ConcurrentAccessException e) {
  logger.error(String.format("user has been authenticated: %s", username), e); // 用户重复登录
} catch (AccountException e) {
  logger.error(String.format("account except: %s", username), e); // 其他账户异常
}
  • shiro用户认证时序图:

授权

shiro访问授权有3种实现方式:api调用,java注解,jsp标签。

在独立应用程序中访问授权通过api调用实现
String role = "schwartz";
Subject currentUser = SecurityUtils.getSubject();
if(currentUser.hasRole(role)) {
  //用户属于角色schwartz
}else{
  //用户不属于角色schwartz
}
在spring框架中可以通过java注解
@RequiresPermissions(value={"log:manage:*"})
public ModelAndView home(HttpServletRequest req) {
  ModelAndView mv = new ModelAndView("home");
  return mv;
}
在JSP页面中还可以直接使用jsp标签
<!-- 使用shiro标签 -->
<shiro:hasPermission name="log:manage:*">
  <a href="<%=request.getContextPath()%>/user/home">操作日志审计</a><br/>
</shiro:hasPermission>
shiro访问授权时序图

注意事项

  1. org.apache.shiro.realm.jdbc.JdbcRealm如果需要在授权时开启权限检查,必须设置permissionsLookupEnabled为true,否则只检查角色。

  2. 用户退出登录时,Shiro用户必须执行logout(),必须要注销Session信息,避免影响下一次用户认证和授权。

    SecurityUtils.getSubject().logout();
    req.getSession().invalidate();
  3. 如果在数据库中存储的用户密码为编码值(如MD5加密),则在发送登录请求时传递的密码参数也必须是MD5加密结果,否则认证失败。

  4. shiro框架只能控制操作权限,不能控制数据权限。数据权限与具体的业务紧密关联,无法通过一个通用的框架完成,通常都是利用关系数据库查询过滤实现。

    对操作权限的控制有2层含义,其一:用户在前端只能看到对应权限的元素;其二:在后端对用户操作进行权限检查。

组件架构

Shiro主要组件包括:Subject,SecurityManager,Authenticator,Authorizer,SessionManager,CacheManager,Cryptography,Realms。

Subject

  • Subject表示与系统交互的对象,可以是登录系统的操作用户,也可能是另外一个软件系统。
  • Subject类图:

SecurityManager

  • SecurityManager是Shiro架构最核心的组件。实际上,SecurityManager就是Shiro框架的控制器,协调其他组件一起完成认证和授权,如下图所示:

  • SecurityManager类图:

Authenticator

  • Authenticator用于认证,协调一个或者多个Realm,从Realm指定的数据源取得数据之后进行执行具体的认证。见org.apache.shiro.authc.pam.ModularRealmAuthenticator源码:

  • Authenticator类图:

Authorizer

  • Authorizer用户访问控制授权,决定用户是否拥有执行指定操作的权限。
    见org.apache.shiro.authz.ModularRealmAuthorizer源码:

  • Authorizer类图:

SessionManager

  • Shiro与生俱来就支持会话管理,这在安全类框架中都是独一无二的功能。即便不存在web容器环境,shiro都可以使用自己的会话管理机制,提供相同的会话API。
  • 13SessionManager类图:

CacheManager

  • 缓存组件,用于缓存认证信息等。
  • CacheManager类图:

Cryptography

Realms

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

使用shiro

在独立应用中使用shiro

下载

  • 在非Web环境的独立应用中使用Shiro时,只需要shiro-core组件。
  • 在Maven项目中的依赖配置如下:
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.3.2</version>
</dependency>
<!-- Shiro uses SLF4J for logging. We'll use the 'simple' binding in this example app. See http://www.slf4j.org for more info. -->
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.6.1</version>
</dependency>

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

数据源配置

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

也就是说,可以根据实际需求及应用的权限管理复杂度灵活选择指定数据源。

在此,以org.apache.shiro.realm.text.IniRealm为例,具体配置如下:

  • shiro.ini:
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================

# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

认证

  • 在Shiro中,认证即执行用户登录,读取指定Realm连接的数据源,以验证用户身份的有效性与合法性。
String name = "lonestarr";
String pass = "vespa";
Subject currentUser = SecurityUtils.getSubject();
if(!currentUser.isAuthenticated()) {
  UsernamePasswordToken token = new UsernamePasswordToken(name, pass);
  token.setRememberMe(true);
  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, pass), 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);
  }
}
logger.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." );

访问授权

  • 在Shiro中,访问授权即验证用户是否具备执行指定操作的权限(角色或权限验证)。
    特别地!在执行访问授权验证之前,必须执行用户认证。
String role = "schwartz";
if(currentUser.hasRole(role)) {
  logger.info(String.format("用户: %s 属于角色:%s", name, role));
}else{
  logger.error(String.format("用户: %s 不属于角色:%s", name, role));
}

String perm = "lightsaber:cc";
if(currentUser.isPermitted(perm)) {
  logger.info(String.format("用户: %s 拥有权限:%s", name, perm));
}else {
  logger.error(String.format("用户:%s 没有权限:%s", name, perm));
}

在web应用中使用shiro

下载

  • 在Maven项目中的依赖配置如下:
<!-- shiro配置 -->
<dependency>
  <groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version></dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.3.2</version>
</dependency>

<!-- 配置日志组件 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.7.25</version></dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>  <version>1.2</version>
</dependency>

特别地!Shiro使用了日志框架slf4j,因此需要对应配置指定的日志实现组件,如:log4j,logback等。
而且,由于shiro-web组件使用apache commons logging组件中的工具类,所以在项目中必须添加commongs logging组件。
否则,程序启动时将会报错:

java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at org.apache.commons.beanutils.ConvertUtilsBean.<init>(ConvertUtilsBean.java:157)
at org.apache.commons.beanutils.BeanUtilsBean.<init>(BeanUtilsBean.java:117)
at org.apache.commons.beanutils.BeanUtilsBean$1.initialValue(BeanUtilsBean.java:68)
at org.apache.commons.beanutils.ContextClassLoaderLocal.get(ContextClassLoaderLocal.java:153)
....

集成Shiro

  • 在Java Web应用中使用Shiro,需要特别的集成方式,不再像在非Web环境的独立应用中使用Shiro那么简单(只需要下载Shiro并添加到项目即可)。
  • 通常,在Java Web应用中集成框架都是从配置web.xml开始的,集成Shiro也不例外。

web.xml:

<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

通常,在Java Web应用中集成第三方框架,都是从Filter开始。Shiro也是如此,即需要将所有请求都经过Shiro指定的Filter进行拦截,这样才能完成用户对指定资源访问的授权验证。

特别地,从Shiro 1.2+版本之后,在Java Web应用中集成Shiro非常简单,甚至都不需要明确指定shiro配置文件的路径,而是直接在web.xml中添加org.apache.shiro.web.env.EnvironmentLoaderListener即可(只需要保证在${webapp}/WEB-INF/目录下存在文件shiro.ini)。

数据源配置

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

  • 也就是说,可以根据实际需求及应用的权限管理复杂度灵活选择指定数据源。

  • 在此,以org.apache.shiro.realm.text.IniRealm为例,具体配置如下:
    shiro.ini:

[main]
# 自定义过滤器sessionFilter = org.chench.test.shiroweb.filter.SessionFilter
authc.loginUrl = /index
ssl.enabled = false

# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

# -----------------------------------------------------------------------------
# The format of each line in the urls section is as follows:
# _URL_Ant_Path_Expression_ = _Path_Specific_Filter_Chain_
# -----------------------------------------------------------------------------
[urls]
/index = anon, sessionFilter
/user/signin = anon
/user/login = anon
/user/** = authc
/home/** = authc
#/admin/** = authc, roles[administrator]
#/rest/** = authc, rest
#/remoting/rpc/** = authc, perms["remote:invoke"]

认证

  • 在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) {
exception = e;
logger.error(String.format("user not found: %s", name), e);
} catch(IncorrectCredentialsException e) {
exception = e;
logger.error(String.format("user: %s pwd: %s error", name, password), e);
} catch (ConcurrentAccessException e) {
exception = e;
logger.error(String.format("user has been authenticated: %s", name), e);
} catch (AuthenticationException e) {
exception = e;
logger.error(String.format("account except: %s", name), e);
}
}

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

授权

  • 需要再三强调!!! Shiro作为权限框架,仅仅只能控制对资源的操作权限,并不能完成对数据权限的业务需求。
  • 而对于Java Web环境下Shiro授权,包含个方面的含义。

其一,对于前端来说,用户只能看到他对应访问权限的元素。在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" %>

其二,当用户执行指定操作(即:访问某个uri资源)时,需要验证用户是否具备对应权限。与在非Java Web环境下一样,需要在后端调用API进行权限(或者角色)检验。如果在Spring框架中集成Shiro,还可以直接通过Java注解方式实现。

api调用

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

在spring框架中集成shiro

下载

  • 在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>

集成Shiro

在Spring框架中集成Shiro,本质上是与Spring IoC容器和Spring MVC框架集成,所以应该分为2部分来说。

  • 与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>
  • 与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类图:

数据源配置

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

Realm类图:

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

  • 在使用org.apache.shiro.realm.jdbc.JdbcRealm时,必须要在关系型数据库中存在3张表,分别是:

    • users表,存放认证用户基本信息,在该表中必须存在2个字段:username,password。

    • roles_permissions表,存放角色和权限定义,在该表中必须存在2个字段:role_name,permission。

    • user_roles表,存放用户角色对应关系,在该表中必须存在2个字段:username,role_name。
      实际上,在更加复杂的应用场景下,通常需要扩展org.apache.shiro.realm.jdbc.JdbcRealm。

认证

在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环境中,用户名和密码参数是通过前端页面进行传递。

授权

  • 操作与web上述一样

  • 在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;
  }
}

Spring集成Shiro注意事项

  • 假设存在如下几个配置文件,分别是:
springDAO.xml:数据源定义
springMVC.xmlSpring MVC配置
springService.xml:其他Spring组件配置
springShiro.xmlShiro相关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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值