说明:
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>
扫描二维码关注公众号,回复:
8535782 查看本文章
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml, classpath:applicationContext-shiro.xml </param-value>
</context-param>
spring配置文件必须写在shiro配置文件上面
自定义角色realm 需要在类上加上@Service注解 不然spring在注入时会报找不到该bean的错误。