0

Spring Security(6)

 1 year ago
source link: https://blog.51cto.com/u_15817148/5890454
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring Security(6)

精选 原创

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

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依赖:

Spring Security(6)_Java

通过模仿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注解注入):

Spring Security(6)_Spring Security_02

运行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值。

访问数据记录:

Spring Security(6)_mongodb_03

不管是Mongodb还是别的NoSQL,比如Redis,原理都是一样的。


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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK