开放平台设计方案与实践
欢迎大家关注我的微信公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。一、背景
随着业务的发展,越来越多的系统需要数据往来。那对外提供的接口也越来越多,而且各个接口散落在不同的项目中被调用,多了的话排查问题困难且混乱。基于这个痛点,我们有必要打造一套开放平台来管理各个api的调用情况。二、开放平台设计
我们先从整体的功能需求来分析,主要有以下几点:开发者身份注册与数据权限范围授权开发者获取相关资料(接口文档、使用说明、对接人联系方式等)平台方接入管理,申请审核流程、服务配置、服务管理、参数配置等平台方运营管理,业务交易管理及统计报表分析安全层面需求,加密、应用秘钥、应用接口权限控制、访问黑白名单、字段脱敏还原等性能方面要求,客户端缓存、服务端缓存、缓存等
这里老周给出自己的一个架构,大家可以参考下:
上面的设计方案更多的是针对比较大型的公司,想要把整个开平的能力建设完善。但市场上更多的是中小型公司,它们没有太多的人力去开发与建设这么全面的开放平台。
那如果是中小型公司,那它们的开放平台如何不费很大精力去实现呢?不管中小型还是大型公司的开放平台,上面说的那个图中其它部分可以省略,但安全机制是必需的,也就是架构图中的统一鉴权。试想一下,作为提供给第三方调用接口的开放平台,如果安全机制不能保障,那外部谁都可以来调用你们公司的内部资源,危害可想而知。
老周下面就来针对不同的业务场景来给出相应的开放平台安全机制的保障,也就是根据不同类型的网站给出相对应的开放平台设计方案。三、小型网站
3。1基于session的登录认证
在传统的用户登录认证中,因为http是无状态的,所以都是采用session方式。用户登录成功,服务端会保存一个session,当然会给客户端一个sessionId,客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId。服务器收到sessionId,找到前期保存的数据,由此得知用户的身份。
对于小型网站,特别是单机系统,基于session的登录认证方案已经够用了,而且简单高效。四、中型网站
随着用户量的增多,上面基于cookiesession的这种模式缺点就显现出来了,这种模式通常是保存在内存中,而且服务从单服务到多服务会面临session共享问题,开销也随即越来越大。
那中型网站的安全认证机制是啥呢?接下来JWT(JSONWebToken)即将登场,关于JWT的概念与原理,老周这里觉得还是有必要说一下。
4。1JWT的概念
4。1。1什么是JWT?
JWT是一个开放的行业标准(RFC7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥私钥对来签名,防止被篡改。
说白了JWT就是一套基于token的身份认证的方案,可以保证安全传输的前提下传送一些基本的信息,以减轻对外部存储的依赖,减少了分布式组件的依赖,减少了硬件的资源。
可实现无状态、分布式的Web应用授权,JWT的安全特性保证了token的不可伪造和不可篡改。
本质上是一个独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以及您可以存储任何其他信息(自包含)。任何人都可以轻松读取和解析,并使用密钥来验证真实性。
4。1。2JWT令牌结构
JWT令牌由三部分组成,每部分中间使用点(。)分隔,比如:xxxxx。yyyyy。zzzzzHeader
头部包括令牌的类型(即JWT)及使用的哈希算法(如HMACSHA256或RSA),例如:
{
alg:HS256,
typ:JWT
}
将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。Payload
第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比如:iss(签发者),exp(过期时间戳),sub(面向的用户)等,也可自定义字段。此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。一个例子:
{
sub:1234567890,
name:微信公众号【老周料架构】,
iat:1516239022
}Signature
第三部分是签名,此部分用于防止jwt内容被篡改。这个部分使用base64url将前两部分进行编码,编码后使用点(。)连接组成字符串,最后使用header中声明签名算法进行签名。
secret:签名所使用的密钥。
HMACSHA256(
base64UrlEncode(header)。base64UrlEncode(payload),secret
)
验签过程描述:获取token值,读取Header部分并Base64解码,得到签名算法。根据以上方法算出签名,如果签名信息不一致,说明是非法的。
4。2JWT的流程
4。3JWT代码案例
如果你们公司有第三方应用接入的开放平台,那可以在里面走相应的接入流程得到appId和appSecret。如果没有的话,那可以简单点与第三方约定相应的appId和appSecret。老周这里假设你们已经约定好了,我这里直接放在请求头里来获取token,还有其它的方式,比如放在请求参数或者cookie里。
4。3。1maven依赖dependencygroupIdcom。auth0groupIdjavajwtartifactIdversion3。4。1versiondependency
4。3。2JWTUtil工具类publicclassJWTUtil{privatestaticStringSECRETEdefaultsecrete;privatestaticStringAPPIDzhifubao;privatestaticStringAPPSECRETE123abc;传入appId、appSecret进行验证paramappId应用idparamappSecret应用密钥return返回一个加密JWTtokenpublicstaticStringgetToken(StringappId,StringappSecret){StringtokenJWT。create()存放payload数据。withClaim(appId,appId)。withClaim(appSecret,appSecret)使用SECRETE对称加密生成signature。sign(Algorithm。HMAC256(SECRETE));returntoken;}验证tokenparamtokenreturnpublicstaticbooleanverifyToken(Stringtoken){HashMapString,StringmapnewHashMap();通过SECRETE和相同的对称加密算法反加密DecodedJWTjwtJWT。require(Algorithm。HMAC256(SECRETE))。build()。verify(token);获得你储存的payload信息StringappIdjwt。getClaim(appId)。asString();StringappSecretjwt。getClaim(appSecret)。asString();if(APPID。equals(appId)APPSECRETE。equals(appSecret)){returntrue;}returnfalse;}}
4。3。3JWTController类RestControllerpublicclassJWTController{RequestMapping(getToken)publicStringgetToken(RequestHeader(appId)StringappId,RequestHeader(appSecret)StringappSecret){returnJWTUtil。getToken(appId,appSecret);}}
4。3。4测试
拓展:这个私钥secrete是固定的,为了加强安全,你甚至可以使用动态的secrete私钥,
例如:动态私钥静态私钥用户的ip,这样即使别人得到了用户的token,也会因为ip不一致而访问失败。
拿到了应用资源服务器的token令牌了,那我们拿这个令牌去访问相应的资源看看。RequestMapping(getResource)publicStringgetResource(StringresourceId){returnresourceId资源获取成功;}
简单模拟一个请求,直接返回该资源获取成功。我们接下来就用postman工具来模拟一下这个资源服务器的这个接口请求。
认证失败了,这是因为我们没有在请求头里填刚刚获取的token。我们把通过调用getToken接口获取的token值放在在请求头,然后认证通过,获取到了资源服务器的资源。
4。3。5继续追问
这里你有可能问了,老周,这里咋就带上token在请求头就可以获取到了资源服务器的资源啊。
我把代码贴出来,你一看就知道了。
这里写了一个token的拦截器,对请求头的token进行验签,通过才放行。ComponentpublicclassTokenInterceptorimplementsHandlerInterceptor{OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{Stringtokenrequest。getHeader(token);if(token!null){booleanresultJWTUtil。verifyToken(token);if(result){System。out。println(通过拦截器);returntrue;}}response。setCharacterEncoding(UTF8);response。setContentType(applicationjson;charsetutf8);try{response。getWriter()。append(认证失败,无效的token令牌!);System。out。println(认证失败,无效的token令牌!);}catch(Exceptione){e。printStackTrace();response。sendError(500);returnfalse;}returnfalse;}}
这里有个拦截器配置类,把需要拦截的api路径放进来,然后会对某个api进行细粒度的管控。ConfigurationpublicclassIntercepterConfigimplementsWebMvcConfigurer{privateTokenInterceptortokenInterceptor;publicIntercepterConfig(TokenInterceptortokenInterceptor){this。tokenInterceptortokenInterceptor;}OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){ListStringexcludePathnewArrayList();excludePath。add(getResource);excludePath。add(static);静态资源registry。addInterceptor(tokenInterceptor)。addPathPatterns()。excludePathPatterns(excludePath);WebMvcConfigurer。super。addInterceptors(registry);}}
这就实现中型网站安全认证机制了,细心的读者可能会发现,这个token是固定的,会存在一些不安全。是的,我上面也说了,可以用动态的secrete私钥或者token过期机制来继续保证更高的安全性。五、大型网站
大型网站的话,针对中型网站的方案就不太可行了,为什么呢?由于大型网站的请求流量很大,而token由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token的签名验签操作也会给cpu带来额外的处理负担。可以采用微服务统一认证方案SpringCloudOAuth2,那什么情况下需要使用OAuth2?第三方授权登录的场景:比如,我们经常登录一些网站或者应用的时候,可以选择使用第三方授权登录的方式,比如:微信授权登录、QQ授权登录、微博授权登录等,这是典型的OAuth2使用场景。单点登录的场景:如果项目中有很多微服务或者公司内部有很多服务,可以专做一个认证中心(充当认证平台色),所有的服务都要到这个认证中心做认证,只做一次登录,就可以在多个授权范围内的服务中自由串行。
5。1OAuth2构建微服务统一认证服务思路
注意:在我们统一认证的场景中,ResourceServer其实就是我们的各种受保护的微服务,微服务中的各种API访问接口就是资源,发起http请求的浏览器就是Client客户端(对应为第三方应用)。
5。1。1搭建认证服务器(AuthorizationServer)
5。1。1。1maven依赖文件
5。1。1。2application。yml文件
5。1。1。3OauthServerApplication9999启动类
5。1。1。4认证服务器配置类
5。1。1。5认证服务器安全配置类
5。1。1。6测试
5。1。1。6。1获取token
http:localhost:9999oauthtoken?clientsecretabcxyzgranttypepasswordusernameadminpassword123456clientidclientriemannendpoint:oauthtoken
获取token携带的参数
clientid:客户端id
clientsecret:客户单密码
granttype:指定使用哪种颁发类型,password
username:用户名
password:密码
5。1。1。6。2校验token
http:localhost:9999oauthchecktoken?token28317df740364bbb8bb312f71fa07802
如果出现以上页面,表明token过期了,设置的是20s。所以要在20s以内校验才会生效。
下面才是token校验成功的效果:
5。1。1。6。3刷新token
http:localhost:9999oauthtoken?granttyperefreshtokenclientidclientriemannclientsecretabcxyzrefreshtoken68582d023a1d4c31ae22ac7e84824d0d
5。1。2搭建资源服务器(希望访问被认证的微服务)
5。1。2。1资源服务ResourceServer配置类
5。1。2。2测试
此测试结果也印证了代码的效果
我们加上带上token测下看看:
5。2OAuth2统一认证服务思考当我们第一次登陆之后,认证服务器颁发token并将其存储在认证服务器中,后期我们访问资源服务器时会携带token,资源服务器会请求认证服务器验证token有效性,如果资源服务器有很多,那么认证服务器压力会很大。另外,资源服务器向认证服务器checktoken,获取的也是用户信息UserInfo,能否把用户信息存储到令牌中,让客户端一直持有这个令牌,令牌的验证也在资源服务器进行,这样避免和认证服务器频繁的交互。我们可以考虑使用JWT进行改造,使用JWT机制之后资源服务器不需要访问认证服务器。
5。3JWT改造统一认证授权中心的令牌存储机制
JWT在上面中型网站那一节说过了,这里就不重复说了,老周直接上代码了。
5。3。1认证服务器端JWT改造(改造主配置类)
5。3。2修改JWT令牌服务方法
5。3。3认证服务器端测试
可以看出,使用jwt令牌生成的accesstoken和上一篇的不一样。
我们用这个网站:https:jwt。ioencodedjwt把该accesstoken进行解码,解码如下:
其他两个验证token、刷新token跟上一篇类似。
5。3。4资源服务器校验JWT令牌
不需要和远程认证服务器交互,添加本地tokenStore。
5。3。5源服务器端测试
这样就完成了资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。六、总结
老周首先从开放平台的整体功能设计来分析了有如下几个要点:开发者认证、开放平台内部管理系统、安全机制以及性能。
但考虑很多公司它们没有太多的人力去开发与建设这么全面的开放平台,故抓住其中的最核心的一点,那就是安全机制。
针对于安全机制来说,不同类型的网站有不同的安全机制保障。小型网站:基于session的登录认证,在小型网站特别是单机系统,这种方案够用了,而且简单高效;中型网站:到了中型网站,服务肯定是分布式部署的,这个时候小型网站中基于session的登录认证方案的缺点就暴露出来了。每个应用服务都需要在session中存储用户身份信息,通过负载均衡将本地的请求分配到另一个应用服务需要将session信息带过去,否则会重新认证。我们还要通过session共享、session黏贴等方案来解决。从而引入了第三方分布式组件,比如redis,增加了系统的复杂性。并且session方案还有另一个缺点,比如基于cookie,移动端不能有效使用等。所以中型网站的话基于JWT的token认证机制,服务端不用存储认证数据,易维护扩展性强,客户端可以把token存在任意地方,并且可以实现web和app统一认证机制。大型网站:到了大型网站,请求量也随之暴涨,中型网站的token认证机制的缺点也逐步暴露出来了,token由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token的签名验签操作也会给cpu带来额外的处理负担。这个时候得采用微服务统一认证方案SpringCloudOAuth2,后面我们又对OAuth2进行了一些优化,因为大型网站的开平请求流量会很大,资源服务器会请求认证服务器验证token有效性,那么认证服务器压力会很大。另外,资源服务器向认证服务器checktoken,获取的也是用户信息UserInfo,能否把用户信息存储到令牌中,让客户端一直持有这个令牌,令牌的验证也在资源服务器进行,这样避免和认证服务器频繁的交互。所以我们后续使用JWT进行改造,使用JWT机制之后资源服务器不需要访问认证服务器。性能以及安全机制都得到了有力保障。
看完希望对你有所帮助,有帮助的话,请不要吝啬你的点赞、评论、收藏,毕竟原创不易。好了,我们下期再见。
孟姜女哭长城真实发生地被人遗忘二千多年后现在终于现身了孟姜女哭长城的故事可以说在中国家喻户晓。其发生地目前全国有几十处,有的地方建成旅游景点。到底哪一处是真实发生地,长期以来一直众说纷云。最近,通过对大量的文献资料进行筛选,无意中……
蒋雯丽一家三口出国度假,穿着普通却气质高级,儿子长得更像他爸在如今这个年代,无论是审美还是时尚观念,都是非常多样化的,在服装单品的选择上还是会随着大众化进行挑选,但是每个人的形象和气质都会有所差别,所以在选择的时候也会发生一定的改变。尤……
小美人鱼真人电影新海报美人鱼渴望水面上世界近日《小美人鱼》真人电影官方发布新海报,哈莉贝利(HalleBailey)扮演的小美人鱼亮相,她渴望水面上的世界。一起来欣赏下吧!新海报也是致敬了1989年动画版的海报,……
荣耀50降级6。0回退4。2荣耀50UI6。0降级4。22022年荣耀50升级到6。0,升级到123版本,但有的软件会闪退,觉得不适合不好用,于是要降回4。0,竟无法回退,手机助理也不行,去服务点也……
一直被模仿,从未被超越!时尚博主三木的穿着有什么值得模仿的?一直被模仿,从未被超越:时尚博主三木的穿着有什么值得模仿的?在中国不管做什么都会有人跟风,有人山寨,即便是做网红,也会有各种各样的人争先恐后地跟着做,可能两个人没有太多的……
三国杀走强盗的路,让强盗无路可走三国杀:走强盗的路,让强盗无路可走(小智戏说)小伙伴们好啊,我是小智。正所谓大鹏一日同风起,扶摇直上九万里。这里先祝各位小伙伴都可以黄盖抓弩,曹昂必闪!兵乐不中,称象四桃……
梦回卢浮宫正在上小学四年级的女儿这学期的第一篇习作主题是推荐一个好地方,最终女儿写的是《卢浮宫》博物馆。在女儿写作的过程中,我的思绪又被带回到五年前在法国旅游时度过的那段美好时光。……
柳传快柳传志和柳青(七)近年,教育行业双减、互联网行业反垄断和交通行业安全审查等等事件,对我国经济发展和社会发展影响深远。当然,这些都是好事,我们要支持!。由于,联想集团和联想控股共同创始……
财富的死亡陷阱之方向陷阱想要拥有巨大的财富,必须学会避开财富的死亡陷阱,这些陷阱碰到一个,就可能会产生对个人产生颠覆性的影响,甚至会导致走向万劫不复的深渊。财富的死亡陷阱有很多,我梳理了18个财……
多吃会变丑的几种食物吃东西也会变丑?那么你是否知道确实有一些食物吃多了就会变得越来越丑?影响颜值的食物我们一定要避开。接下来为大家讲解什么食物会让你越吃越丑。一:家中的自来水烧开后会留下厚厚……
秋天,少吃红薯南瓜多吃它,一次做好放冰箱,随吃随取,特省事导语:入秋后,少吃红薯南瓜,多吃它!一次做好存放冰箱,随吃随取,特省事!大家好,我是傻姐美食,生活中唯有美食和爱不可辜负,立秋后农村集市上的瓜果蔬菜品种很多,吃应季蔬菜和……
人间清醒文案,做个人间清醒的人,狠狠打开格局人间清醒文案,做个人间清醒的人,狠狠打开格局!Hi,我是现黎小姐。做个人间清醒的人,狠狠打开格局。今天给大家整理收集了一些人间清醒的文案,让你人间清醒。1。人……