上节讲了在JAVA SE环境下搭建shiro框架,这节主要在web环境下搭建shiro框架对web前端页面进行权限的控制。
一,整合spring,springmvc框架。
1.导入spring的相关jar包。
2.配置web.xml文件
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
3.在classpath路径下创建spring的配置文件applicationContext.xml和spring mvc的配置文件mvc.xml
mvc.xml文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/">property>
<property name="suffix" value=".jsp">property>
bean>
<context:component-scan base-package="cn.shinelon.controller">context:component-scan>
beans>
接着自行创建mvc.xml文件,至此,基本完成了spring,springmvc框架的整合
下面,重点是applicationContext.xml文件,以及web.xml文件的配置。
二,整合shiro框架
首先,我们来简单讲解一下shiro框架整合的原理。
对于一个安全框架,它控制着用户对web资源的访问,当服务器启动,用户发来请求,首先应该经过安全验证,哪些资源用户可以直接匿名访问,哪些资源用户需要登录验证身份才能访问,这里我们想到了在web.xml文件中配置过滤器,用户从前台进行请求,首先经过springmvc的servlet请求,请求到相应的资源,这是到了shiro过滤器,必须经过验证,需要强调的时,web.xml文件的filter只是一个代理类DelegatingFilterProxy,它需要到applicationContext.xml文件中找到与filter-name名相同的bean进行权限的管理,这里又有一个问题,为什么要使用代理类,这个类有什么作用?使用代理类可以降低代码的耦合度,提高代码的重用性,比如,你要使用spring security安全框架的时候,web.xml文件中的filter代理类无需更改,它只是一个代理,只需改动相应的bean就可以了,这样一来,在web.xml中对权限的控制有一个总的代理,一切的外来请求首先通过这个代理来进行权限的验证,比如,你要去找一个公司找人,首先要经过前台保卫室的身份认证,经过了验证你就可以找到你要找的人,就是这个道理。在这里有一个代理类DelegatingFilterProxy,首先我们先看一下它的源码:
public class DelegatingFilterProxy extends GenericFilterBean {
private String contextAttribute;
private WebApplicationContext webApplicationContext;
private String targetBeanName;
private boolean targetFilterLifecycle = false;
private volatile Filter delegate;
private final Object delegateMonitor = new Object();
.......
}
首先说一下targetBeanName这个属性,从字面意思上我们可以看出来它是目标bean的名称,也就是说默认情况下,filter-name的名字必须与bean的名字一致,但在这里也可以显示的指出目标bean的名字,也就是说通过设置targetBeanName这个属性的值可以不用使他们的值一致。下面看一段源码就会更加清楚它的工作原理了:
@Override
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
// If no target bean name specified, use filter name.
if (this.targetBeanName == null) {
this.targetBeanName = getFilterName();
}
// Fetch Spring root application context and initialize the delegate early,
// if possible. If the root application context will be started after this
// filter proxy, we'll have to resort to lazy initialization.
WebApplicationContext wac = findWebApplicationContext();
if (wac != null) {
this.delegate = initDelegate(wac);
}
}
}
}
接着,我们来说另一个核心配置,在applicationContext.xml文件中配置SecurityManager。
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="sessionMode" value="native"/>
<property name="realm" ref="jdbcRealm"/>
bean>
这里创建securityManager安全管理器bean,它有几个属性,cacheManager这个是缓存管理,这个缓存技术,是hibernate中默认的缓存框架,第二个属性sessionMode这个是session的模式,在这里作用不大,就不做详细讲解了,最后一个属性是real,它引入了一个realm的bean实例,这里我们在src文件中创建一个ShiroRealm类实现realm接口,代码如下:
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.realm.Realm;
public class ShiroRealm implements Realm {
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken arg0)
throws AuthenticationException {
// TODO Auto-generated method stub
return null;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean supports(AuthenticationToken arg0) {
// TODO Auto-generated method stub
return false;
}
}
接着在spring配置文件中注入bean
<bean id="jdbcRealm" class="cn.shinelon.shiro.ShiroRealm">bean>
然后就是配置cacheManager,这里面需要加入另外一个配置文件ehcache.xml,这个文件读者可以在hibernate的jar包中找到拿到项目的src目录下。
id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
除此之外,applicationContext.xml文件中还有一个重要的配置,就是上文所说的filter代理类的目标bean:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/logon.jsp"/>
<property name="successUrl" value="/success.jsp"/>
<property name="unauthorizedUrl" value="/error.jsp"/>
<util:map>
<entry key="aName" value-ref="someFilterPojo"/>
util:map>
property> -->
<property name="filterChainDefinitions">
<value>
/logo.jsp = anon
/** = authc
value>
property>
bean>
第一个属性是引入了安全管理器,第二个属性是登录页面它的值是anon,也就是所有的用户不用登录就可以匿名访问的,不需要任何权限,第三个属性是当登录成功后跳转的页面,最后一个没有经过验证后跳转的页面。
最后,applicationContext.xml中的完整代码如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="sessionMode" value="native"/>
<property name="realm" ref="jdbcRealm"/>
bean>
<bean id="jdbcRealm" class="cn.shinelon.shiro.ShiroRealm">bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<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>
<bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
<property name="securityManager" ref="securityManager"/>
bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/logon.jsp"/>
<property name="successUrl" value="/success.jsp"/>
<property name="unauthorizedUrl" value="/error.jsp"/>
<util:map>
<entry key="aName" value-ref="someFilterPojo"/>
util:map>
property> -->
<property name="filterChainDefinitions">
<value>
/logo.jsp = anon
/** = authc
value>
property>
bean>
<context:component-scan base-package="cn.shinelon"/>
beans>
在这里,shiro使用Ant风格的url匹配规则
/aa?.jsp中的?只匹配一个字符,表示aab.jsp页面,只能匹配b这一个字符。
/aa*.jsp中的 *号表示匹配零个或者多个字符,表示以aa开头的所有jsp页面
/** 是路径,表示匹配web根目录下的所有路径。
shiro中url的匹配顺序采用第一个匹配优先的原则。
接着就是测试了,在根目录下创建相应的登录页面logon.jsp,success.jsp,error.jsp页面,由于没有连接数据库,只做一个简单的测试,我们在浏览器中输入localhost:8080/项目名/logon.jsp时可以直接访问,但是,如果直接访问success.jsp就会重定向到logon.jsp,这说明用户没有权限访问。至此,我们就搭建完了web环境下的shiro框架。