SSM整合shiro安全框架(多个realms)

说明:

shiro.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!-- 配置使用自定义认证器,可以实现多Realm认证,并且可以指定特定Realm处理特定类型的验证 -->
   <bean id="authenticator"
      class="com.tbs.system.shiro.CustomizedModularRealmAuthenticator">
      <!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 -->
      <property name="authenticationStrategy">
         <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
      </property>
   </bean>
   <!-- 配置緩存管理器 -->
   <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
      <!-- 指定 ehcache 的配置文件,下面会给到 -->
      <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml" />
   </bean>
   <!-- 配置进行授权和认证的 Realm,要新增一个java类来实现,下面会有,class=包名.类名,init-methood是初始化的方法 -->
   <!-- 配置 Shiro 的 SecurityManager Bean. -->
   <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
      <property name="cacheManager" ref="cacheManager" />
      <property name="authenticator" ref="authenticator"></property>
      <property name="realms">
         <list>
            <ref bean="userRealm" />
            <ref bean="workerRealm" />
         </list>
      </property>
   </bean>

   <!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
   <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

   <!-- 配置 ShiroFilter bean: 该 bean 的 id 必须和 web.xml 文件中配置的 shiro filter 的 
      name 一致 -->
   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
      <!-- 装配 securityManager -->
      <property name="securityManager" ref="securityManager" />
      <!-- 配置登陆页面 -->
      <property name="loginUrl" value="/" />
      <property name="filters">
            <map>
                <!--退出过滤器-->
                <entry key="logout" value-ref="systemLogoutFilter" />
            </map>
        </property>
      <!-- 登陆成功后的一面 -->
      <!-- <property name="successUrl" value="success.jsp"/> -->
      <!-- <property name="unauthorizedUrl" value="/shiro-unauthorized.jsp"/> -->
      <!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截. -->
      <property name="filterChainDefinitions">
         <value>
            <!-- 配置登出: 使用 logout 过滤器 /shiro-logout = logout /shiro-* = anon /user.jsp 
               = roles[user] /admin.jsp = roles[admin] /** = authc -->
            <!-- bill/** = authc worker/login = authc -->
            <!-- /*/worker/** = authc
            /*/bill/** = authc -->
            <!-- /** = authc -->
            
              /worker/login = anon 
             /worker/logout = logout
            /static/** = anon
              /** = authc    
         </value>
      </property>
   </bean>
</beans>

spring配置文件加入:

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

ehcache.xml

<!--
<diskStore>   : 当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口)
<diskStore path="">     : 用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是*.data和*.index
name : "缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里)
maxElementsInMemory  : 缓存最大个数。
eternal="false"   : 对象是否永久有效,一但设置了,timeout将不起作用。 (必须设置)
maxEntriesLocalHeap="1000"  : 堆内存中最大缓存对象数,0没有限制(必须设置)
maxEntriesLocalDisk= "1000"   : 硬盘最大缓存个数。
overflowToDisk="false"   : 当缓存达到maxElementsInMemory值是,是否允许溢出到磁盘(必须设置)(内存不足时,是否启用磁盘缓存。)
diskSpoolBufferSizeMB  : 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskPersistent="false"  : 磁盘缓存在JVM重新启动时是否保持(默认为false)
timeToIdleSeconds="0"  : 导致元素过期的访问间隔(秒为单位),即当缓存闲置n秒后销毁。 当eternal为false时,这个属性才有效,0表示可以永远空闲,默认为0
timeToLiveSeconds="600"   : 元素在缓存里存在的时间(秒为单位),即当缓存存活n秒后销毁. 0 表示永远存在不过期
memoryStoreEvictionPolicy="LFU" : 当达到maxElementsInMemory时,如何强制进行驱逐默认使用"最近使用(LRU)"策略,其它还有先入先出FIFO,最少使用LFU,较少使用LRU
diskExpiryThreadIntervalSeconds :磁盘失效线程运行时间间隔,默认是120秒。
clearOnFlush   : 内存数量最大时是否清除。-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />

    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="10000"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>

    <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
           maxElementsInMemory="100"
           eternal="false"
           timeToLiveSeconds="600"
           overflowToDisk="false"/>

</ehcache>

web.xml加入:

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:applicationContext.xml,
                classpath:applicationContext-shiro.xml
   </param-value>
</context-param>
<!-- shiro -->
<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>

自定义认证器:

package com.tbs.system.shiro;

import java.util.ArrayList;
import java.util.Collection;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
/**
 * @author beibei
 * 自定义Authenticator
 * 注意,当需要分别定义处理普通用户和管理员验证的Realm时,对应Realm的全类名应该包含字符串“User”,或者“Admin”。
 * 并且,他们不能相互包含,例如,处理普通用户验证的Realm的全类名中不应该包含字符串"Admin"。
 */
public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator{
   @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        // 判断getRealms()是否返回为空
        assertRealmsConfigured();
        // 强制转换回自定义的CustomizedToken
        CustomizedToken customizedToken = (CustomizedToken) authenticationToken;
        // 登录类型
        String loginType = customizedToken.getLoginType();
        // 所有Realm
        Collection<Realm> realms = getRealms();
        // 登录类型对应的所有Realm
        Collection<Realm> typeRealms = new ArrayList<Realm>();
        for (Realm realm : realms) {
            if (realm.getName().contains(loginType))
                typeRealms.add(realm);
        }

        // 判断是单Realm还是多Realm
        if (typeRealms.size() == 1)
            return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);
        else
            return doMultiRealmAuthentication(typeRealms, customizedToken);
    }
}

添加登陆角色类型:

public enum LoginType {
   WORKER("worker"),  USER("user");

    private String type;

    private LoginType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return this.type.toString();
    }
}

认证过程:

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tbs.user.Mapper.userMapper;
import com.tbs.user.pojo.userPO;
import com.tbs.user.serviceImp.userServiceImp;
import com.tbs.worker.Mapper.workerMapper;
import com.tbs.worker.pojo.workerPO;

@Service("userRealm")
public class userRealm extends AuthorizingRealm{
   
   @Autowired
   private userServiceImp userService;
   
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
      // TODO 自动生成的方法存根
      System.out.println("暂时无权限设置");
      return null;
   }

    /*
     * 用户验证
     * 
     */
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
      // TODO 自动生成的方法存根
      CustomizedToken token = (CustomizedToken) arg0;
      String userName =(String) token.getPrincipal();
      Map<String, Object> map = new HashMap<String, Object>();
      map.put("userName", userName);
      String password = new String((char[])token.getCredentials());
      //凭证,用户的密码,具体加密方式用户自己实现,什么都不做就是原文

        //Roles:用户拥有的角色标识(角色名称,admin,account,customer_service),
        // 字符串格式列表:用户拥有多个角色的可能

        //Permissions:用户拥有的权限标识(每个权限唯一标识,比如主键或者权限唯一标识编码),
        // 字符串格式列表:用户拥有多个权限的可能
      
      //查询用户信息
      userPO userPO = null;
      userPO = userService.list(map).get(0);
      if(userPO == null){
         throw new UnknownAccountException("账号不存在");
      }

        //密码错误
        if (!password.equals(userPO.getPassWord())) {
            throw new UnknownAccountException("密码错误");
        }
      //第一个参数是user对象,第二个是指从数据库中获取的password,第三个参数是当前realm的名称。
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userPO, password, getName());
        return info;
   }

}

认证时需要加入登陆角色类型:

CustomizedToken  token = new CustomizedToken((String)map.get("username"), (String)map.get("password"),WORKER_LOGIN_TYPE);

注意:

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext.xml, classpath:applicationContext-shiro.xml </param-value>

</context-param>

spring配置文件必须写在shiro配置文件上面

自定义角色realm 需要在类上加上@Service注解 不然spring在注入时会报找不到该bean的错误。

发布了13 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39701913/article/details/82740663