手记

Spring Security(6)

您好,我是湘王,这是我的慕课手记,欢迎您来,欢迎您再来~


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

/**
 * MongoDaoSupport
 *
 * @author 湘王
 */
@Component
public class MongoDaoSupport<T> {
    @Autowired
    private MongoTemplate mongoTemplate;

    // 插入数据
    public boolean insert(PersistentRememberMeToken token) {
        if (Objects.isNull(token)) {
            return false;
        }

        Object object = mongoTemplate.save(token);
        if (Objects.nonNull(object)) {
            return true;
        }

        return false;
    }
}

 

然后再在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原理都是一样的

 



 

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



0人推荐
随时随地看视频
慕课网APP