spring cloud oauth2 中的并发问题

2,068 阅读2分钟
原文链接: www.jianshu.com

坚持是一种态度,优秀是一种习惯!

    最近一直在倒腾oauth2,oauth2是一种开放授权的协议。具体的原理不在本篇文章叙述,如同学们有兴趣,可以下次详细介绍。本篇主要讲述这两天遇到的获取token的并发问题。

出现的问题

     废话少说,上干货。oauth2的一个主要作用是获取token(有四种方式),并发出现的现象是当有同一个client_id,secret并发访问/oauth/token时报

Incorrect result size: expected 1, actual 2 using jdbctokenstore错误。通过debug发现是oauth中的DefaultTokenService中的createAccessToken方法抛出来的异常

上图中的函数跟进去,发现在获取token之前首先会根据client_id去数据库中查询是否token,当数据库中有>1条记录的时候,抛异常。

       此时,数据库中却出现了2条记录,why???

原因

createAccessToken方法的大概的逻辑是先删除后插入,数据库中有2条记录,有时候会更多,怀疑是createAccessToken没有做并发控制,当多个线程同时进入createAccessToken方法时会出现多条记录的现象。于是写了个脚本验证自己的推断:

结果发现,如果同时启动10个线程,同一个client_id会出现10天记录(有时候低于10,纯属看运气),验证了我的推断。

解决方案:

    问题根源找到了,就得想办法解决。在spring-security-oauth git的issue上发现有好几个人也遇到同样的问题,具体产生多条记录的,有个老外总结如下:

看不懂英文的,可以去Google翻译,但是作为一个程序猿,还是要有阅读技术类文档的能力。

按照老外的说法是,oauth2目前只支持单线程,认为现实的应用场景也只有单线程用户,wtf!!!殊不知还有脚本这玩意。

目前总体的解决方案有如下2种:

1、继承DefaultTokenService 在createAccessToken方法加上sychronized关键字。但是这种方案有个弊端在于,oauth服务器如果是分布式部署还是会出现并发问题

2、继承DefaultTokenService 将createAccessToken事务级别调SERIALIZABLE。这种方案的弊端在于使用的底层数据库得支持事务

欢迎关注我的公众号Porce2018哈。之后继续分享工作中遇到的各种技术问题。