1.导入jar包
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
2.在web.xml中配置拦截器
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<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>
注意:
此处<async-supported>会报错,需要在<web-app>中配置
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
3.在springmvc.xml中配置shiro
<!--spring 自定参数解析器-->
<bean id="springAnnotationResolver" class="org.apache.shiro.spring.aop.SpringAnnotationResolver" />
<!--开启Spring AOC Shiro注解支持-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
<property name="advice">
<bean class="org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor">
<property name="methodInterceptors">
<list>
<bean class="项目名.module.shiro.aop.AuthenticatedAnnotationMethodInterceptor">
<constructor-arg ref="springAnnotationResolver" />
</bean>
<bean class="org.apache.shiro.authz.aop.RoleAnnotationMethodInterceptor">
<constructor-arg ref="springAnnotationResolver" />
</bean>
<bean class="org.apache.shiro.authz.aop.PermissionAnnotationMethodInterceptor">
<constructor-arg ref="springAnnotationResolver" />
</bean>
<bean class="org.apache.shiro.authz.aop.UserAnnotationMethodInterceptor">
<constructor-arg ref="springAnnotationResolver" />
</bean>
<bean class="org.apache.shiro.authz.aop.GuestAnnotationMethodInterceptor">
<constructor-arg ref="springAnnotationResolver" />
</bean>
</list>
</property>
</bean>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm">
<bean class="项目名.module.shiro.AuthorizingRealm"/>
</property>
<property name="cacheManager">
<bean class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
</property>
</bean>
<!-- shiro工厂bean配置 过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- shiro的核心安全接口 -->
<property name="securityManager" ref="securityManager"/>
<!--登录的url-->
<property name="loginUrl" value="/"/>
</bean>
<!--管理shiro bean生命周期-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 启用Spring IOC容器Shiro注解,当TestTram类有实现某个接口,而TestProxyClass类中配置的类对象是TestTram时(而不是TestTram实现的接口),这时候你需要配置proxyTargetClass=true-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<!-- 开启aop,对类代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
4.在module>shiro下,新建SecurityManager
package 项目名.module.shiro;
import 项目名.exception.SystemException;
import 项目名.module.Configuration;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
public class SecurityManager extends DefaultWebSecurityManager {
//开启redis
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Override
protected void stopSession(Subject subject) {
Session session = subject.getSession();
super.stopSession(subject);
SessionManager sessionManager = (SessionManager) super.getSessionManager();
sessionManager.delete(session);
String mappingKey;
SimpleToken.Principal principal = (SimpleToken.Principal) subject.getPrincipal();
if(principal instanceof SimpleToken.Role){
mappingKey = Configuration.SYSTEM_SESSION_ADMIN_MAPPING_NAMESPACE;
}else if(principal instanceof SimpleToken.Role){
mappingKey = Configuration.SYSTEM_SESSION_SHOP_MAPPING_NAMESPACE;
}else {
throw new SystemException("未知的角色信息");
}
this.redisTemplate.delete(String.format("%s:%s", mappingKey,((SimpleToken.Principal) subject.getPrincipal()).getId()));
}
}
注:需要配置的相关文件有
(1)SessionManager
package 项目名.module.shiro;
import 项目名.module.Configuration;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.*;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.util.AntPathMatcher;
import org.apache.shiro.util.PatternMatcher;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
public class SessionManager extends AbstractValidatingSessionManager {
private final Logger logger = LogManager.getLogger(SessionManager.class);
private SessionFactory sessionFactory;
private SessionDAO sessionDAO;
public SessionManager(){
this.sessionFactory = new SimpleSessionFactory();
}
@Override
protected void onInvalidation(org.apache.shiro.session.Session s, InvalidSessionException ise, SessionKey key) {
super.onInvalidation(s, ise, key);
this.onInvalidation(key);
}
@Override
protected void onExpiration(org.apache.shiro.session.Session s, ExpiredSessionException ese, SessionKey key) {
super.onExpiration(s, ese, key);
this.onInvalidation(key);
}
@Override
protected void onExpiration(org.apache.shiro.session.Session session) {
if (session instanceof SimpleSession) {
((SimpleSession) session).setExpired(true);
}
this.onChange(session);
}
@Override
protected void afterExpired(org.apache.shiro.session.Session session) {
this.delete(session);
}
@Override
protected org.apache.shiro.session.Session retrieveSession(SessionKey key) {
Serializable sessionId = this.getSessionId(key);
org.apache.shiro.session.Session session = this.retrieveSession(sessionId);
return session;
}
@Override
protected org.apache.shiro.session.Session doCreateSession(SessionContext initData) throws AuthorizationException {
org.apache.shiro.session.Session session = ((initData != null && initData.getHost() != null) ? new Session(initData.getHost()) : new Session());
create(session,initData);
return session;
}
@Override
protected Collection<org.apache.shiro.session.Session> getActiveSessions() {
Collection<org.apache.shiro.session.Session> active = this.sessionDAO.getActiveSessions();
return active != null ? active : Collections.emptySet();
}
private void onInvalidation(SessionKey key) {
}
protected void delete(org.apache.shiro.session.Session session) {
this.sessionDAO.delete(session);
}
protected void onChange(org.apache.shiro.session.Session session) {
if(this.sessionDAO.readSession(session.getId()) != null){
this.sessionDAO.update(session);
}
}
protected void create(org.apache.shiro.session.Session session, SessionContext initData) {
if(WebUtils.isWeb(initData)){
HttpServletRequest request = (HttpServletRequest) WebUtils.getRequest(initData);
if(this.isLoginRequest(request)){
this.sessionDAO.create(session);
}
}
}
private boolean isLoginRequest(ServletRequest servletRequest){
PatternMatcher pathMatcher = new AntPathMatcher();
String requestURI = WebUtils.getPathWithinApplication(WebUtils.toHttp(servletRequest));
for(String path : Configuration.SYSTEM_SHIRO_LOGIN_URL){
if(pathMatcher.matches(path,requestURI)){
return true;
}
}
return false;
}
protected Serializable getSessionId(SessionKey sessionKey) {
String token = null;
if(WebUtils.isWeb(sessionKey)){
HttpServletRequest httpServletRequest = (HttpServletRequest) WebUtils.getRequest(sessionKey);
String authorization = httpServletRequest.getHeader(Configuration.SYSTEM_REQUEST_AUTHORIZATION);
if(!StringUtils.isBlank(authorization)){
String authorizationOriginal = new String(Base64.decodeBase64(httpServletRequest.getHeader(Configuration.SYSTEM_REQUEST_AUTHORIZATION)));
if(authorizationOriginal.contains(":")){
String[] authorizationArray = authorizationOriginal.split(":");
if(!StringUtils.isBlank(authorizationArray[0]) && !isLoginRequest(httpServletRequest)){
token = authorizationArray[0];
}
}
}
}
return sessionKey.getSessionId() == null ? token : sessionKey.getSessionId();
}
protected org.apache.shiro.session.Session newSessionInstance(SessionContext context) {
return this.getSessionFactory().createSession(context);
}
protected org.apache.shiro.session.Session retrieveSession(Serializable sessionId) throws UnknownSessionException {
return sessionId == null ? null : this.sessionDAO.readSession(sessionId);
}
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionDAO getSessionDAO() {
return this.sessionDAO;
}
public void setSessionDAO(SessionDAO sessionDAO) {
this.sessionDAO = sessionDAO;
}
}
(2)Session
package 项目名.module.shiro;
import org.apache.shiro.session.mgt.SimpleSession;
import java.util.UUID;
public class Session extends SimpleSession {
public Session() {
this.setId(UUID.randomUUID().toString().replace("-",""));
}
public Session(String host) {
super(host);
this.setId(UUID.randomUUID().toString().replace("-",""));
}
}
(3)SimpleToken
Principal 是一个原始角色,之后的User、Role等等都是根据实际需求,继承自Principal 的
package项目名.module.shiro;
import org.apache.shiro.authc.AuthenticationToken;
import java.io.Serializable;
public class SimpleToken implements AuthenticationToken {
private Principal principal;
private String credentials;
public SimpleToken(Principal principal, String credentials){
this.principal = principal;
this.credentials = credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public Object getCredentials() {
return this.credentials;
}
public static class Principal implements Serializable {
private Integer id;
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Principal{" +
"id=" + id +
'}';
}
}
public static class User extends Principal implements Serializable {
public User(Integer id) {
super.id = id;
}
@Override
public String toString() {
return "User{" +
"id=" + super.getId() +
'}';
}
}
public static class Technician extends Principal implements Serializable {
public Technician(Integer id) {
super.id = id;
}
@Override
public String toString() {
return "Technician{" +
"id=" + super.getId() +
'}';
}
}
public static class Role extends Principal implements Serializable {
public Role(Integer id) { super.id = id; }
@Override
public String toString() {
return "Role{"+"id="+super.getId()+"}";
}
}
public static class Admin extends Principal implements Serializable{
public Admin(Integer id) {
super.id=id;
}
@Override
public String toString() {
return "Admin{"+"id="+super.getId()+"}";
}
}
public static class Shop extends Principal implements Serializable{
public Shop(Integer id) {
super.id=id;
}
@Override
public String toString() {
return "Shop{"+"id="+super.getId()+"}";
}
}
}
(4)Configuration配置redis参数
// 超级管理员
public static final String SYSTEM_SESSION_ADMIN_MAPPING_NAMESPACE = "pedicure:session:manager:admin:mapping";
// 商家
public static final String SYSTEM_SESSION_SHOP_MAPPING_NAMESPACE = "pedicure:session:manager:shop:mapping";
//登录的路径 {}中的是所有登录路径的String数组
public static final String[] SYSTEM_SHIRO_LOGIN_URL = new String[]{"/role/login","/technician/login"};
//session路径
public static final String SYSTEM_SESSION_NAMESPACE = "pedicure:session:manager";
5.在module>shiro下,新建AuthorizingRealm
个人认为这个部分很重要,因为这里是你获取角色信息的地方,后续一系列的权限操作,都从这里开始
因此,在第一处注释处,要将getPrimaryPrincipal()得到的数据转化为SimpleToken中对应的自定义类型,比如“SimpleToken.Admin”就是SimpleToken中的Admin角色
package 项目名.module.shiro;
import 项目名.exception.SystemException;
import 项目名.mapper.RoleMapper;
import 项目名.pojo.Role;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class AuthorizingRealm extends org.apache.shiro.realm.AuthorizingRealm {
@Autowired
private RoleMapper roleMapper;
public AuthorizingRealm() {
super.setAuthenticationTokenClass(SimpleToken.class);
}
@Override
public String getName() {
return "customRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
int loginId = -1;
if(principals.getPrimaryPrincipal() instanceof SimpleToken.Admin){
// 从 principals获取主身份信息
loginId = ((SimpleToken.Admin) principals.getPrimaryPrincipal()).getId();
}else if(principals.getPrimaryPrincipal() instanceof SimpleToken.Shop){
loginId = ((SimpleToken.Shop) principals.getPrimaryPrincipal()).getId();
}
System.out.println("loginId:" + loginId);
// 从数据库获取到权限数据
Role role = roleMapper.selectByPrimaryKey(loginId);
// 根据身份信息获取权限信息(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型)
simpleAuthorizationInfo.addRole(role.getRoleName());
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws SystemException {
AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(), authenticationToken.getCredentials(), super.getName());
return info;
}
}
6.在module>shiro下,新建SubjectDAO
这里是从redis中拿到对应角色的mappingKey ,它的作用相当于id,是唯一识别标识,因此继承自 principal 的 SimpleToken.Admin 要和 Configuration中的参数路径一一对应
package net.$51zhiyuan.dev.yunzuliao_backStage.module.shiro;
import 项目名.exception.SystemException;
import 项目名.module.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
public class SubjectDAO extends DefaultSubjectDAO {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Override
protected void saveToSession(Subject subject) {
Session session = subject.getSession(false);
if (session == null && !CollectionUtils.isEmpty(subject.getPrincipals())) {
session = subject.getSession();
String mappingKey;
SimpleToken.Principal principal = (SimpleToken.Principal) subject.getPrincipal();
if(principal instanceof SimpleToken.Admin){
mappingKey = Configuration.SYSTEM_SESSION_ADMIN_MAPPING_NAMESPACE;
}else if(principal instanceof SimpleToken.Shop){
mappingKey = Configuration.SYSTEM_SESSION_SHOP_MAPPING_NAMESPACE;
}else {
throw new SystemException("未知的角色信息");
}
mappingKey = String.format("%s:%s", mappingKey,((SimpleToken.Principal) subject.getPrincipal()).getId());
String historySessionId = (String) this.redisTemplate.opsForValue().get(mappingKey);
System.out.println("his:"+historySessionId);
System.out.println("sessionId:"+session.getId());
if(!StringUtils.isBlank(historySessionId) && !session.getId().equals(historySessionId)){
String sessionKey = String.format("%s:%s",Configuration.SYSTEM_SESSION_NAMESPACE,historySessionId);
System.out.println(sessionKey);
this.redisTemplate.delete(sessionKey);
}
this.redisTemplate.opsForValue().set(mappingKey,session.getId());
}
super.saveToSession(subject);
}
}
7.在module>shiro>aop下,新建AuthenticatedAnnotationMethodInterceptor
package 项目名.module.shiro.aop;
import org.apache.shiro.aop.AnnotationResolver;
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
public class AuthenticatedAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
public AuthenticatedAnnotationMethodInterceptor(){
super(new AuthenticatedAnnotationHandler());
}
public AuthenticatedAnnotationMethodInterceptor(AnnotationResolver resolver){
super(new AuthenticatedAnnotationHandler(),resolver);
}
}
8.配置applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置 读取properties文件 jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
<!-- 配置 读取properties文件 redis.properties -->
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
<!-- 配置 读取properties文件 redis.properties -->
<context:property-placeholder location="classpath:config/global.properties" ignore-unresolvable="true"/>
<!-- 配置 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${jdbc.maxWait}"></property>
</bean>
<!-- 配置SqlSessionFactory -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis核心配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
<property name="mapperLocations" value="classpath:项目名/mapper/xml/*.xml" />
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="insert*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="list*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="check*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* *.*ServiceImpl.*(..))" id="txPc"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config>
<!-- 配置Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 设置Mapper扫描包 -->
<property name="basePackage" value="项目名.mapper" />
</bean>
<!-- 设置jedis -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="hostName" value="${redis.hostName}" />
<property name="port" value="${redis.port}" />
<property name="timeout" value="${redis.timeout}" />
<property name="database" value="${redis.database}" />
<property name="password" value="${redis.password}" />
<property name="usePool" value="${redis.usePool}" />
<property name="poolConfig">
<bean class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="10" />
<property name="maxIdle" value="10" />
<property name="minIdle" value="2" />
<property name="maxWaitMillis" value="15000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="numTestsPerEvictionRun" value="3" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
</bean>
</property>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
</bean>
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg ref="redisTemplate" />
<property name="defaultExpiration" value="0" />
</bean>
</beans>
9.在module>shiro下,新建SessionDAO
package 项目名.module.shiro;
import 项目名.module.Configuration;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class SessionDAO extends AbstractSessionDAO {
private String sessionNamespace = Configuration.SYSTEM_SESSION_NAMESPACE;
private RedisTemplate<Serializable,Object> redisTemplate;
private Session storeSession(Serializable id, Session session) {
if (id == null) {
throw new NullPointerException("id argument cannot be null.");
}
this.redisTemplate.opsForValue().set(String.format("%s:%s",this.sessionNamespace,id),session);
return session;
}
@Override
protected Serializable doCreate(Session session) {
this.storeSession(session.getId(), session);
return session.getId();
}
@Override
public Session readSession(Serializable sessionId) throws UnknownSessionException {
return this.doReadSession(sessionId);
}
@Override
protected Session doReadSession(Serializable sessionId) {
ValueOperations valueOperations = this.redisTemplate.opsForValue();
Session session = (Session) valueOperations.get(String.format("%s:%s",this.sessionNamespace,sessionId));
return session;
}
@Override
public void update(Session session) throws UnknownSessionException {
this.storeSession(session.getId(), session);
}
@Override
public void delete(Session session) {
if (session == null) {
throw new NullPointerException("session argument cannot be null.");
}
Serializable id = session.getId();
if (id != null) {
this.redisTemplate.delete(String.format("%s:%s",this.sessionNamespace,id));
}
}
@Override
public Collection<Session> getActiveSessions() {
HashOperations hashOperations = this.redisTemplate.opsForHash();
List<Session> sessions = hashOperations.values(this.sessionNamespace);
Collection<Session> values = sessions;
if (CollectionUtils.isEmpty(values)) {
return Collections.emptySet();
} else {
return Collections.unmodifiableCollection(values);
}
}
public String getSessionNamespace() {
return sessionNamespace;
}
public void setSessionNamespace(String sessionNamespace) {
this.sessionNamespace = sessionNamespace;
}
public RedisTemplate<Serializable, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
}
到此,框架搭建基本完成,但是在运行的时候出现了一个bug
No bean named 'shirofilter' available
这是因为在web.xml中,没有找到springmvc.xml这个路径,从而无法加载,因此需要在web.xml中配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</context-param>
欢迎大家补充改正
ps: