• Spring Security(6)


    您好,我是湘王,这是我的CSDN博客,欢迎您来,欢迎您再来~

    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 {
    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 map = (LinkedHashMap) 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 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,原理都是一样的。


    感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

  • 相关阅读:
    鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统项目背景
    【BUG】cmd运行wmic提示‘wmic‘ 不是内部或外部命令
    PMM2 MySQL监控管理工具
    软考成绩什么时候查?怎么查?能复查吗?
    一种超轻量级神经网络加速器实现
    Nexus【应用 01】上传jar包到私有Maven仓库的两种方法:手动 Upload 和 mvn deploy 命令(配置+操作流程)
    Linux学习-49-列出进程调用或打开的文件信息(lsof命令)
    Docker-镜像的备份迁移及私有仓库的搭建
    帆软报表之填报报表
    架构师怎样绘制系统架构蓝图?
  • 原文地址:https://blog.csdn.net/lostrex/article/details/128071119