spring shiro 集成

1、向spring项目中添加shiro相关的依赖

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
View Code

2、在web.xml配置ShiroFilter

<!-- shiro过虑器,DelegatingFilterProx会从spring容器中找shiroFilter -->
<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>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
View Code

 3、建立一个 spring 的配置文件 spring-shiro.xml

  a、使用 import 标签把此文件引入为spring的配置文件

<import resource="classpath:spring-shiro.xml"></import>

  b、配置spring-shiro.xml文件

    <!-- shiro 拦截器配置 -->
    <!-- ShiroFilter 名字必须要和web.xml中配置的名字一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/>
        <property name="unauthorizedUrl" value="/nopermission.jsp"/>
        <!-- filterChainDefinitions 相当于.ini文件中的[urls] -->
        <property name="filterChainDefinitions">
            <value>
                /logout=logout
                /**=authc
            </value>
        </property>
    </bean>
    <!--shiro权限异常处理 -->
    <!-- 上面对“/nopermission.jsp”的配置不会生效,因为 spring 默认会抛出异常到页面;需要添加下面这个配置才可以生效-->
    <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">redirect:/nopermission.jsp</prop>
            </props>
        </property>
    </bean>

    <!-- 配置安全管理器SecurityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <!-- 给shiro添加缓存配置 -->
        <property name="cacheManager" ref="cacheManager"></property>
    </bean>
    <!-- 配置自定义的Realm -->
    <bean id="userRealm" class="cn.wolfcode.shiro.realm.UserRealm">
        <!-- 加密器 -->
        <property name="credentialsMatcher" ref="credentialsMatcher" />
    </bean>
    <!-- 在自定义的realm那个类里还要指定盐 -->
    <bean id="credentialsMatcher"
          class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <!-- 加密算法 -->
        <property name="hashAlgorithmName" value="md5" />
        <!-- 散列次数 -->
        <property name="hashIterations" value="3" />
    </bean>

    <!-- 开启aop,对类代理;并开启shiro注解支持 -->
    <aop:config proxy-target-class="true"></aop:config>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!-- 缓存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManager" ref="ehCacheManager"/>
    </bean>
    <bean id="ehCacheManager" class ="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:shiro-ehcache.xml" />
        <property name="shared" value="true"></property>
    </bean>

4、实现自己的realm

public class UserRealm extends AuthorizingRealm {
    @Override
    public String getName() {
        return "UserRealm";
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        if(!"admin".equals(principal)){
            return null;
        }
        Employee currentUser = new Employee();
        currentUser.setName(principal);
        currentUser.setPassword("1");
        currentUser.setAdmin(true);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(currentUser, currentUser.getPassword(),getName());
        return authenticationInfo;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Employee currentUser = (Employee) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        List<String> roles = new ArrayList<String>();
        roles.addAll(Arrays.asList("HR MGR","ORDER MGR"));
        authorizationInfo.addRoles(roles);
        List<String> perms = new ArrayList<String>();
        perms.addAll(Arrays.asList("employee:view","employee:delete"));
        authorizationInfo.addStringPermissions(perms);
        return authorizationInfo;
    }
}
View Code

5、 实现登陆方法

Suject 会自动创建,不需要我们配置;相应的登陆方法也会自动调用,不需要我们写。

    //此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
    @RequestMapping("/login")
    public String login(Model model, HttpServletRequest req) throws  Exception{
        //如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
        String exceptionClassName = (String) req.getAttribute("shiroLoginFailure");
        //根据shiro返回的异常类路径判断,抛出指定异常信息
        if(exceptionClassName!=null){
            if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
                //最终会抛给异常处理器

                model.addAttribute("errorMsg", "账号不存在");
            } else if (IncorrectCredentialsException.class.getName().equals(
                    exceptionClassName)) {
                model.addAttribute("errorMsg", "用户名/密码错误");
            } else {
                //最终在异常处理器生成未知错误.
                model.addAttribute("errorMsg", "其他异常信息");
            }
        }
        //登陆失败还到login页面
        return "forward:/login.jsp";
    }
View Code

6、缓存管理(登陆时把当前用户的权限缓存起来,之后不需要再次查询)

  a、添加依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.8</version>
</dependency>
View Code

  b、securityManager引用缓存管理器(如上)

  c、配置缓存管理器,并指定缓存框架配置文件路径(如上)

    ehcache版本在2.5.0以下,需要配置如下:
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
      <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"></property>
    </bean>
    ehcache版本在2.5.0以上,需要配置如下:
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
      <property name="cacheManager" ref="ehCacheManager"/>
    </bean>
    <bean id="ehCacheManager" class ="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
      <property name="configLocation" value="classpath:shiro-ehcache.xml" />
      <property name="shared" value="true"></property>
    </bean>

  d、配置 shiro-ehcache.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <defaultCache
            maxElementsInMemory="1000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

7、清除缓存

  如果用户正常退出,缓存自动清空;如果用户非正常退出,缓存自动清空。

  如果修改了用户的权限,而用户不退出系统,修改的权限无法立即生效;用户退出并再次登陆系统时,shiro会自动调用realm从数据库重新获取权限数据,才会使修改的权限得以生效。

  如果在修改权限后想要立即生效,需要清除缓存,可以调用realm的clearCache方法。

// 在realm中定义该方法,在角色或权限service中,delete或者update方法里来调用
// 清除缓存
public void clearCached() {
     PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
     super.clearCache(principals);
}

 

posted @ 2017-11-04 12:59  zhuangrunwei  阅读(221)  评论(0编辑  收藏  举报