Spring Security(6)

打印 上一主题 下一主题

主题 813|帖子 813|积分 2439

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
 
Spring Security使用MySQL保存cookie记录虽然方便,但是目前更多的主流互联网应用都是用NoSQL来保存非业务数据的,Spring Security也应该可以实现这个功能。之前Spring Security官方并不支持使用NoSQL来保存cookie,但这个问题对于一个爱钻研的码农来说应该只是个小CASE——毕竟只要有代码,就没有搞不定的问题——受JdbcTokenRepositoryImpl的启发,查看其源码,可以发现JdbcDaoSupport只是用来提供数据源,无实际意义,而PersistentTokenRepository才是要实现的接口。
JdbcTokenRepositoryImpl的源码非常简单,看懂了就能照着写出Mongo的实现。题外话:阅读源码是个能够很快提高开发能力的捷径,如Spring框架、Spark源码等等。
下面就来开始咱们的NoSQL改造DIY。
首先安装并运行mongodb(我用的是mongodb-4.2.6),可以是虚拟机,也可以是Docker。
再修改项目的pom.xml文件,增加mongodb依赖:

 
 
 
 
通过模仿JdbcDaoSupport,来自定义自己的MongoDaoSupport:
  1. /**
  2. * MongoDaoSupport
  3. *
  4. * @author 湘王
  5. */
  6. @Component
  7. public class MongoDaoSupport<T> {
  8.     @Autowired
  9.     private MongoTemplate mongoTemplate;
  10.     // 插入数据
  11.     public boolean insert(PersistentRememberMeToken token) {
  12.         if (Objects.isNull(token)) {
  13.             return false;
  14.         }
  15.         Object object = mongoTemplate.save(token);
  16.         if (Objects.nonNull(object)) {
  17.             return true;
  18.         }
  19.         return false;
  20.     }
  21. }
复制代码
 
 
然后再在MongoDaoSupport中增加两个重要的方法,让它支持Mongodb:
  1.     // 查询数据
  2.     public PersistentRememberMeToken getTokenBySeries(String series) {
  3. //        // 如果是通过字符串方式诸葛插入字段值,那么通过mongoTemplate.findOne()得到的就是一个LinkedHashMap
  4. //        LinkedHashMap<String, String> map = (LinkedHashMap<String, String>) mongoTemplate
  5. //                .findOne(query, Object.class, "collectionName");
  6. //        return new PersistentRememberMeToken(map.get("username"), map.get("series"),
  7. //                map.get("tokenValue"), DateUtils.format()map.get("date"));
  8.         Query query = new Query(Criteria.where("series").is(series));
  9. //        // 这里原路返回PersistentRememberMeToken对象,不会是LinkedHashMap
  10. //        Object object = mongoTemplate.findOne(query, PersistentRememberMeToken.class);
  11. //        return (PersistentRememberMeToken) obejct;
  12.         return mongoTemplate.findOne(query, PersistentRememberMeToken.class);
  13.     }
  14.     // 更新数据
  15.     public boolean updateToken(String series, String tokenValue, Date lastUsed) {
  16.         Query query = new Query(Criteria.where("series").is(series));
  17.         Update update = new Update();
  18.         update.set("tokenValue", tokenValue);
  19.         update.set("date", lastUsed);
  20. //        // 这里不能用DateUtils.parse(new Date()),否则getTokenBySeries()方法会抛出非法参数异常
  21. //        update.set("date", DateUtils.parse(new Date()));
  22.         Object object = mongoTemplate.updateMulti(query, update, PersistentRememberMeToken.class);
  23.         if (Objects.nonNull(object)) {
  24.             return true;
  25.         }
  26.         return false;
  27.     }
复制代码
 
 
然后再定义MongoTokenRepositoryImpl:
  1. /**
  2. * 自定义实现token持久化到mongodb
  3. *
  4. * @author 湘王
  5. */
  6. public class MongoTokenRepositoryImpl implements PersistentTokenRepository {
  7.     @Autowired
  8.     private MongoDaoSupport<PersistentRememberMeToken> mongoDaoSupport;
  9.     @Override
  10.     public void createNewToken(PersistentRememberMeToken token) {
  11.         mongoDaoSupport.insert(token);
  12.     }
  13.     @Override
  14.     public void updateToken(String series, String tokenValue, Date lastUsed) {
  15.         mongoDaoSupport.updateToken(series, tokenValue, lastUsed);
  16.     }
  17.     @Override
  18.     public PersistentRememberMeToken getTokenForSeries(String series) {
  19.         return mongoDaoSupport.getTokenBySeries(series);
  20.     }
  21.     @Override
  22.     public void removeUserTokens(String username) {
  23.     }
  24. }
复制代码
 
 
接着在WebSecurityConfiguration中用自定义的MongoTokenRepositoryImpl代替JdbcTokenRepositoryImpl:
  1. // NoSQL方式实现记住我
  2. @Bean
  3. public PersistentTokenRepository persistentTokenRepository() {
  4.     // 自定义mongo方式实现
  5.     MongoTokenRepositoryImpl mongoTokenRepository = new MongoTokenRepositoryImpl();
  6.     return mongoTokenRepository;
  7. }
复制代码
 
 
或者就直接(需要通过@Service注解注入):

 
 
 
 
运行postman测试,可以看到通过MongoDB实现了对cookie信息的存储与修改。
如果mongodb中多出了_class字段,可以加上额外的配置:
  1. /**
  2. * 去除_class字段
  3. *
  4. * @author 湘王
  5. */
  6. @Configuration
  7. public class MongoConfiguration implements InitializingBean {
  8.     @Autowired
  9.     @Lazy
  10.     private MappingMongoConverter mappingMongoConverter;
  11.     @Override
  12.     public void afterPropertiesSet() {
  13.         mappingMongoConverter
  14.                 .setTypeMapper(new DefaultMongoTypeMapper(null));
  15.     }
  16. }
复制代码
 
 
多次运行可发现访问记录值的规律:
1、同一用户会有多条访问记录
如果每次都明确执行login方法,那么每次都会产生不同的记录,否则只会更新同一条记录的tokenValue和date值;
若token有效且未执行login方法,那么将更新最后一次产生的记录的tokenValue和date值。
2、这说明token条数是与login方法执行次数一一对应的;
3、只要token不失效,仅更新同一条记录series的token值。
 
访问数据记录:

 
 
 
不管是Mongodb还是别的NoSQL,比如Redis,原理都是一样的。
 
 
 
 
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表