SpringMVC配置sa-Token

首先贴下官方文档,官方sa-token文档;看了一圈都是集成SpringBoot,我用bean注入看起来是先例哦哈哈,好咯,不跟你多bb,直接上代码

代码我放在了GITEE中了需要自取,传送门

  1. 改applicationContext.xml(只有增加的哦)
  <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:redis.properties"/>
 <!-- Sa-Token-->
    <bean class="org.springframework.boot.autoconfigure.EnableAutoConfiguration" abstract="true">
    </bean>
    <bean class="cn.dev33.satoken.spring.SaBeanRegister"/>
    <bean class="cn.dev33.satoken.spring.SaBeanInject">

        <property name="config" ref="sa-token"/>
    </bean>

 <!--自己看SaAloneRedisInject重写的路径-->
    <bean class="top.jacktgq.controller.SaAloneRedisInject">

    </bean>


    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="300"/> <!--最大能够保持idel状态的对象数-->
        <property name="maxTotal" value="60000"/><!--最大分配的对象数-->
        <property name="testOnBorrow" value="true"/><!--当调用borrow Oject方法时,是否进行有效性检查-->
    </bean>


    <bean primary="true" id="redisConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:hostName="${redis.host}"
          p:port="${redis.port}"
          p:database="${redis.database}"/>

    <bean name="saTokenDao" class="cn.dev33.satoken.dao.SaTokenDaoRedisJackson">

    </bean>


    <!--sa-token配置-->
    <bean id="sa-token" class="cn.dev33.satoken.config.SaTokenConfig">
        <!--token名称 (同时也是cookie名称)-->
        <property name="tokenName" value="satoken"></property>
        <!--token有效期,单位s 默认30天, -1代表永不过期-->
        <property name="timeout" value="2592000"></property>
        <!--token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒-->
        <property name="activityTimeout" value="-1"></property>
        <!--是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)-->
        <property name="isConcurrent" value="false"></property>
        <!--在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)-->
        <property name="isShare" value="true"></property>
        <!--token风格-->
        <property name="tokenStyle" value="uuid"></property>
        <!--是否输出操作日志-->
        <property name="isLog" value="true"/>
        <property name="sso" ref="sso"/>


    </bean>


    <!--# SSO-相关配置-->
    <bean id="sso" class="cn.dev33.satoken.config.SaSsoConfig">
        <!--  # SSO-Server端 统一认证地址-->
        <property name="authUrl" value="http://xka.com:8883/sso/auth"/>
        <!--# 是否打开单点注销接口-->
        <property name="isSlo" value="true"/>
    </bean>
  1. 增加redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.password=
redis.database=1
redis.maxActive=300
redis.maxWait=1000
redis.testOnBorrow=true
redis.timeout=100000

sa-token.alone-redis=6666
sa-token.alone-redis.host=6976

fep.local.cache.capacity =10000
  1. 重写SaAloneRedisInject类的方法,至于为什么重写,是因为,他有一个地方要获取SpringBoot的配置的 host,但是我们是SpringMVC的故而就直接重写它
package top.jacktgq.controller;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;

import cn.dev33.satoken.dao.SaTokenDaoRedisJackson;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Lettuce;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import top.jacktgq.utils.PropertiesLoader;

/**
 * 为 SaTokenDao 单独设置Redis连接信息 
 * @author kong
 */
@Configuration
public class SaAloneRedisInject implements EnvironmentAware {

	/**
	 * 配置信息的前缀 
	 */
	public static final String ALONE_PREFIX = "sa-token.alone-redis";
	
	/**
	 * Sa-Token 持久层接口 
	 */
	@Autowired(required = false)
	public SaTokenDao saTokenDao;



	/**
	 * 开始注入 
	 */
	@Override
	public void setEnvironment(Environment environment) {
		try {
			// 如果为空或者默认实现,则不进行任何操作 
			if(saTokenDao == null || saTokenDao instanceof SaTokenDaoDefaultImpl) {
				return;
			}
			// 如果配置文件不包含相关配置,则不进行任何操作 
			/*if(environment.getProperty(ALONE_PREFIX + ".host") == null) {
				return;
			}*/
			
			// ------------------- 开始注入 
			
			// 获取cfg对象 
			//RedisProperties cfg = Binder.get(environment).bind(ALONE_PREFIX, RedisProperties.class).get();
			RedisProperties cfg = getSaAloneRedisConfig();
			// 1. Redis配置 
			RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
			redisConfig.setHostName(cfg.getHost());
			redisConfig.setPort(cfg.getPort());
			redisConfig.setDatabase(cfg.getDatabase());
			redisConfig.setPassword(RedisPassword.of(cfg.getPassword())); 
			
			// 2. 连接池配置 
			GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
			// pool配置 
			Lettuce lettuce = cfg.getLettuce();
			if(lettuce.getPool() != null) {
				RedisProperties.Pool pool = cfg.getLettuce().getPool();
				// 连接池最大连接数
				poolConfig.setMaxTotal(pool.getMaxActive());	
				// 连接池中的最大空闲连接 
				poolConfig.setMaxIdle(pool.getMaxIdle());   	
				// 连接池中的最小空闲连接
				poolConfig.setMinIdle(pool.getMinIdle());		
				// 连接池最大阻塞等待时间(使用负值表示没有限制)
				poolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
			}
			LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
			// timeout 
			if(cfg.getTimeout() != null) {
				builder.commandTimeout(cfg.getTimeout());
			}
			// shutdownTimeout 
			if(lettuce.getShutdownTimeout() != null) {
				builder.shutdownTimeout(lettuce.getShutdownTimeout());
			}
			// 创建Factory对象 
			LettuceClientConfiguration clientConfig = builder.poolConfig(poolConfig).build();
			LettuceConnectionFactory factory = new LettuceConnectionFactory(redisConfig, clientConfig);
			factory.afterPropertiesSet();
			
			// 3. 开始初始化 SaTokenDao 
			// 如果是SaTokenDaoRedis
			try {
				Class.forName("cn.dev33.satoken.dao.SaTokenDaoRedis");
				SaTokenDaoRedis dao = (SaTokenDaoRedis)saTokenDao;
				dao.isInit = false;
				dao.init(factory);
				return;
			} catch (ClassNotFoundException e) {
			}
			// 如果是SaTokenDaoRedisJackson
			try {
				Class.forName("cn.dev33.satoken.dao.SaTokenDaoRedisJackson");
				SaTokenDaoRedisJackson dao = (SaTokenDaoRedisJackson)saTokenDao;
				dao.isInit = false;
				dao.init(factory);
				return;
			} catch (ClassNotFoundException e) {
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 骗过编辑器,增加配置文件代码提示
	 * 自定义编写
	 * @return 配置对象
	 */
	@ConfigurationProperties(prefix = ALONE_PREFIX)
	public RedisProperties getSaAloneRedisConfig() {
		RedisProperties redisProperties =new RedisProperties();
		PropertiesLoader propertiesLoader = new PropertiesLoader("redis.properties");
		redisProperties.setHost(propertiesLoader.getProperty("redis.host"));
		redisProperties.setPort(Integer.parseInt(propertiesLoader.getProperty("redis.port")));
		redisProperties.setDatabase(Integer.parseInt(propertiesLoader.getProperty("redis.database")));
		redisProperties.setPassword(propertiesLoader.getProperty("redis.password"));
		return redisProperties;
	}
	
}

  1. Sa-Token持久层接口 SaTokenDaoRedis
package top.jacktgq.controller;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaFoxUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Sa-Token持久层接口 [Redis版 (使用JDK默认序列化方式)] 
 * 
 * @author kong
 *
 */
@Component
public class SaTokenDaoRedis implements SaTokenDao {

	/**
	 * String专用 
	 */
	public StringRedisTemplate stringRedisTemplate;	

	/**
	 * Objecy专用 
	 */
	public RedisTemplate<String, Object> objectRedisTemplate;

	/**
	 * 标记:是否已初始化成功
	 */
	public boolean isInit;
	
	@Autowired
	public void init(RedisConnectionFactory connectionFactory) {
		// 指定相应的序列化方案 
		StringRedisSerializer keySerializer = new StringRedisSerializer();
		JdkSerializationRedisSerializer valueSerializer = new JdkSerializationRedisSerializer();
		// 构建StringRedisTemplate
		StringRedisTemplate stringTemplate = new StringRedisTemplate();
		stringTemplate.setConnectionFactory(connectionFactory);
		stringTemplate.afterPropertiesSet();
		// 构建RedisTemplate
		RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
		template.setConnectionFactory(connectionFactory);
		template.setKeySerializer(keySerializer);
		template.setHashKeySerializer(keySerializer);
		template.setValueSerializer(valueSerializer);
		template.setHashValueSerializer(valueSerializer);
		template.afterPropertiesSet();

		// 开始初始化相关组件 
		if(this.isInit == false) {
			this.stringRedisTemplate = stringTemplate;
			this.objectRedisTemplate = template;
			this.isInit = true;
		}
	}
	
	
	/**
	 * 获取Value,如无返空 
	 */
	@Override
	public String get(String key) {
		return stringRedisTemplate.opsForValue().get(key);
	}

	/**
	 * 写入Value,并设定存活时间 (单位: 秒)
	 */
	@Override
	public void set(String key, String value, long timeout) {
		if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE)  {
			return;
		}
		// 判断是否为永不过期 
		if(timeout == SaTokenDao.NEVER_EXPIRE) {
			stringRedisTemplate.opsForValue().set(key, value);
		} else {
			stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
		}
	}

	/**
	 * 修改指定key-value键值对 (过期时间不变) 
	 */
	@Override
	public void update(String key, String value) {
		long expire = getTimeout(key);
		// -2 = 无此键 
		if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
			return;
		}
		this.set(key, value, expire);
	}
	
	/**
	 * 删除Value 
	 */
	@Override
	public void delete(String key) {
		stringRedisTemplate.delete(key);
	}

	/**
	 * 获取Value的剩余存活时间 (单位: 秒) 
	 */
	@Override
	public long getTimeout(String key) {
		return stringRedisTemplate.getExpire(key);
	}

	/**
	 * 修改Value的剩余存活时间 (单位: 秒) 
	 */
	@Override
	public void updateTimeout(String key, long timeout) {
		// 判断是否想要设置为永久
		if(timeout == SaTokenDao.NEVER_EXPIRE) {
			long expire = getTimeout(key);
			if(expire == SaTokenDao.NEVER_EXPIRE) {
				// 如果其已经被设置为永久,则不作任何处理 
			} else {
				// 如果尚未被设置为永久,那么再次set一次
				this.set(key, this.get(key), timeout);
			}
			return;
		}
		stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
	}
	
	
	/**
	 * 获取Object,如无返空 
	 */
	@Override
	public Object getObject(String key) {
		return objectRedisTemplate.opsForValue().get(key);
	}

	/**
	 * 写入Object,并设定存活时间 (单位: 秒) 
	 */
	@Override
	public void setObject(String key, Object object, long timeout) {
		if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE)  {
			return;
		}
		// 判断是否为永不过期 
		if(timeout == SaTokenDao.NEVER_EXPIRE) {
			objectRedisTemplate.opsForValue().set(key, object);
		} else {
			objectRedisTemplate.opsForValue().set(key, object, timeout, TimeUnit.SECONDS);
		}
	}

	/**
	 * 更新Object (过期时间不变) 
	 */
	@Override
	public void updateObject(String key, Object object) {
		long expire = getObjectTimeout(key);
		// -2 = 无此键 
		if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
			return;
		}
		this.setObject(key, object, expire);
	}

	/**
	 * 删除Object 
	 */
	@Override
	public void deleteObject(String key) {
		objectRedisTemplate.delete(key);
	}

	/**
	 * 获取Object的剩余存活时间 (单位: 秒)
	 */
	@Override
	public long getObjectTimeout(String key) {
		return objectRedisTemplate.getExpire(key);
	}

	/**
	 * 修改Object的剩余存活时间 (单位: 秒)
	 */
	@Override
	public void updateObjectTimeout(String key, long timeout) {
		// 判断是否想要设置为永久
		if(timeout == SaTokenDao.NEVER_EXPIRE) {
			long expire = getObjectTimeout(key);
			if(expire == SaTokenDao.NEVER_EXPIRE) {
				// 如果其已经被设置为永久,则不作任何处理 
			} else {
				// 如果尚未被设置为永久,那么再次set一次
				this.setObject(key, this.getObject(key), timeout);
			}
			return;
		}
		objectRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
	}


	
	/**
	 * 搜索数据 
	 */
	@Override
	public List<String> searchData(String prefix, String keyword, int start, int size) {
		Set<String> keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*");
		List<String> list = new ArrayList<String>(keys);
		return SaFoxUtil.searchList(list, start, size);
	}
	
	
}

  1. 最后一点就是配置拦截器的了,@EnableWebMvc这个注解一定要加,不然没有用,我因为这个问题困扰2天
package top.jacktgq.controller;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.jacktgq.security.util.StpMemberUtil;

import java.util.Arrays;

@Configuration
@EnableWebMvc//开启SpringMVC支持,如无此注解,重写WebMvcConfigurerAdapter类的方法无效
@ComponentScan("top.jacktgq.controller")
public class JthinkTokenConfig implements WebMvcConfigurer {
	// 注册sa-token的拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 启用注解可以和下面路由拦截器(SaRouteInterceptor)同时使用
		registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");

		// 注册路由拦截器,自定义验证规则
		registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> {
			// 登录验证 -- 排除多个路径
			SaRouter.match(Arrays.asList("/admin/index/**"),
					Arrays.asList("/static/**", "/system/adminlogin", "/system/dologin", "/adminlogout"),
					() -> StpUtil.checkLogin());

		/*	// 角色认证 -- 拦截以 admin 开头的路由,必须具备[admin]角色或者[super-admin]角色才可以通过认证
			SaRouter.match("/admin/**", () -> StpUtil.checkRoleOr("admin", "super-admin"));

			// 权限认证 -- 不同模块, 校验不同权限
			SaRouter.match("/user/**", () -> StpUtil.checkPermission("user"));
			SaRouter.match("/admin/**", () -> StpUtil.checkPermission("admin"));
			SaRouter.match("/goods/**", () -> StpUtil.checkPermission("goods"));
			SaRouter.match("/orders/**", () -> StpUtil.checkPermission("orders"));
			SaRouter.match("/notice/**", () -> StpUtil.checkPermission("notice"));
			SaRouter.match("/comment/**", () -> StpUtil.checkPermission("comment"));

			// 匹配 restful 风格路由
			SaRouter.match("/article/get/{id}", () -> StpUtil.checkPermission("article"));*/

			// 在多账号模式下,可以使用任意StpUtil进行校验
			SaRouter.match(Arrays.asList("/member/**"),
					Arrays.asList("/member/login", "/member/dologin", "/member/register", "/member/logout"),
					() -> StpMemberUtil.checkLogin());

		})).addPathPatterns("/**");
	}


	/** 注册 [Sa-Token全局过滤器] */
	@Bean
	public SaServletFilter getSaServletFilter() {
		return new SaServletFilter()
				.addInclude("/**")
				.addExclude("/sso/*", "/favicon.ico")
				.setAuth(obj -> {
					if(StpUtil.isLogin() == false) {
						String back = SaFoxUtil.joinParam(SaHolder.getRequest().getUrl(), SpringMVCUtil.getRequest().getQueryString());
						SaHolder.getResponse().redirect("/sso/login?back=" + SaFoxUtil.encodeUrl(back));
						SaRouter.back();
					}
				})
				;
	}


}

最后,上面基本上都配置好了,总结就是多看源码,多看文档,如果有老鸟发现博客有问题的话,大家评论一下,愚人节快乐

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello Bug

谢谢老板,老板大气,老板硬邦邦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值