您好 ,我是湘王 ,这是我的博客园 ,欢迎您来 ,欢迎您再来~
SpringSecurity使用MySQL保存cookie记录虽然方便 ,但是目前更多的主流互联网应用都是用NoSQL来保存非业务数据的 ,Spring Security也应该可以实现这个功能 。之前SpringSecurity官方并不支持使用NoSQL来保存cookie ,但这个问题对于一个爱钻研的码农来说应该只是个小CASE——毕竟只要有代码 ,就没有搞不定的问题——受JdbcTokenRepositoryImpl的启发 ,查看其源码 ,可以发现JdbcDaoSupport只是用来提供数据源 ,无实际意义 ,而PersistentTokenRepository才是要实现的接口 。
JdbcTokenRepositoryImpl的源码非常简单,看懂了就能照着写出Mongo的实现 。题外话:阅读源码是个能够很快提高开发能力的捷径 ,如Spring框架 、Spark源码等等 。
下面就来开始咱们的NoSQL改造DIY 。
首先安装并运行mongodb(我用的是mongodb-4.2.6) ,可以是虚拟机,也可以是Docker 。
再修改项目的pom.xml文件 ,增加mongodb依赖:
通过模仿JdbcDaoSupport ,来自定义自己的MongoDaoSupport:
然后再在MongoDaoSupport中增加两个重要的方法 ,让它支持Mongodb:
// 查询数据
public PersistentRememberMeToken getTokenBySeries(String series) {
// // 如果是通过字符串方式诸葛插入字段值 ,那么通过mongoTemplate.findOne()得到的就是一个LinkedHashMap
// LinkedHashMap<String, String> map = (LinkedHashMap<String, String>) mongoTemplate
// .findOne(query, Object.class, "collectionName");
// return new PersistentRememberMeToken(map.get("username"), map.get("series"),
// map.get("tokenValue"), DateUtils.format()map.get("date"));
Query query = new Query(Criteria.where("series").is(series));
// // 这里原路返回PersistentRememberMeToken对象 ,不会是LinkedHashMap
// Object object = mongoTemplate.findOne(query, PersistentRememberMeToken.class);
// return (PersistentRememberMeToken) obejct;
return mongoTemplate.findOne(query, PersistentRememberMeToken.class);
}
// 更新数据
public boolean updateToken(String series, String tokenValue, Date lastUsed) {
Query query = new Query(Criteria.where("series").is(series));
Update update = new Update();
update.set("tokenValue", tokenValue);
update.set("date", lastUsed);
// // 这里不能用DateUtils.parse(new Date()) ,否则getTokenBySeries()方法会抛出非法参数异常
// update.set("date", DateUtils.parse(new Date()));
Object object = mongoTemplate.updateMulti(query, update, PersistentRememberMeToken.class);
if (Objects.nonNull(object)) {
return true;
}
return false;
}
然后再定义MongoTokenRepositoryImpl:
/**
* 自定义实现token持久化到mongodb
*
* @author 湘王
*/
public class MongoTokenRepositoryImpl implements PersistentTokenRepository {
@Autowired
private MongoDaoSupport<PersistentRememberMeToken> mongoDaoSupport;
@Override
public void createNewToken(PersistentRememberMeToken token) {
mongoDaoSupport.insert(token);
}
@Override
public void updateToken(String series, String tokenValue, Date lastUsed) {
mongoDaoSupport.updateToken(series, tokenValue, lastUsed);
}
@Override
public PersistentRememberMeToken getTokenForSeries(String series) {
return mongoDaoSupport.getTokenBySeries(series);
}
@Override
public void removeUserTokens(String username) {
}
}
接着在WebSecurityConfiguration中用自定义的MongoTokenRepositoryImpl代替JdbcTokenRepositoryImpl:
// NoSQL方式实现记住我
@Bean
public PersistentTokenRepository persistentTokenRepository() {
// 自定义mongo方式实现
MongoTokenRepositoryImpl mongoTokenRepository = new MongoTokenRepositoryImpl();
return mongoTokenRepository;
}
或者就直接(需要通过@Service注解注入):
运行postman测试 ,可以看到通过MongoDB实现了对cookie信息的存储与修改 。
如果mongodb中多出了_class字段 ,可以加上额外的配置:
/**
* 去除_class字段
*
* @author 湘王
*/
@Configuration
public class MongoConfiguration implements InitializingBean {
@Autowired
@Lazy
private MappingMongoConverter mappingMongoConverter;
@Override
public void afterPropertiesSet() {
mappingMongoConverter
.setTypeMapper(new DefaultMongoTypeMapper(null));
}
}
多次运行可发现访问记录值的规律:
1 、同一用户会有多条访问记录
如果每次都明确执行login方法 ,那么每次都会产生不同的记录 ,否则只会更新同一条记录的tokenValue和date值;
若token有效且未执行login方法 ,那么将更新最后一次产生的记录的tokenValue和date值 。
2 、这说明token条数是与login方法执行次数一一对应的;
3 、只要token不失效 ,仅更新同一条记录series的token值 。
访问数据记录:
不管是Mongodb还是别的NoSQL,比如Redis ,原理都是一样的 。
感谢您的大驾光临!咨询技术 、产品 、运营和管理相关问题 ,请关注后留言 。欢迎骚扰,不胜荣幸~
声明:本站所有文章 ,如无特殊说明或标注 ,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用 、采集 、发布本站内容到任何网站 、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益 ,可联系我们进行处理 。