Spring Security OAuth2 总结

330 阅读5分钟


项目地址

后端

github.com/publicdevop…

前端 Demo (Angular)

github.com/publicdevop…

注:demo账户:用户名root@gmail.com密码root

背景

鉴于已经有大量关于 OAuth2的文章,本文主要是笔者进行实践当中的心得与笔记,并不会太深入OAuth2协议的细节。千言万语都在代码中,如有不足之处,请在评论区留言或者在GitHub issue中反馈。

项目简介

oauth2service是一个基于spring boot + security oauth2 + jwt的oauth2认证授权微服务。项目提供Client和Resource Owner的相关api操作接口,并且提供了定制化的Authorization code以实现完整的前后端分离。你可以在docker中方便的下载打包好的镜像,并且轻松的启动它。除此之外,配套的swagger文档可以来帮助你通过swagger editor直接调用api。项目有比较全面的测试覆盖,可以根据你自己的需求进行定制或者改动。

注1:swagger目前还只有英文版本,后续会有中文版本发布。

技术术语

  • Authentication(验证): 你是不是我的用户?
  • Authorization(授权):虽然你是我的用户,但是我给予了你什么操作权限 ?第一方应用授权用户或者用户授权第三方应用来执行特定的操作。
  • First Party : 我是用户的所有者,我是第一方应用
  • Third Party : 第三方应用,我只想获得用户的一部分内容,我并不是用户的所有者
  • OAuth2 : 一个Authentication和Authorization的协议,致力于将用户的登录信息(用户名与密码)集中管理,并且在不需要传输登录信息的前提下,允许Third Party获取用户授权的内容。

注:笔者并不同意OAuth2只是Authorization协议的观点,取决于你是First Party还是Third Party,Third Party的确只有Authorization(这里是指用户授权第三方应用)。
  • Client : 这里并不是指用户而是任何应用程序包括第一方和第三方
  • Resource Owner :用户
  • Authorization(Authentication)Server : 对尝试登录用户进行Authentication和Authorization
  • 的服务端
  • Resource Server : 用户所拥有的资源,资源服务
  • Client Credentials flow : 任何应用程序通过ID和Secret来登录,你可以把它当作机器用户
  • Password flow : Client Credentials +用户名与密码。用户通过Client(这里是第一方应用)登录
  • Authorization code flow : 最常见的应用场景,在用户已登录的状态下授权第三方应用获得用户资源
  • Implicit flow : 这个已经不再推荐
  • Refresh token flow : 与Password flow联合使用来避免用户频繁登录

注:Client credentials flow 并不可以添加这个选项,如果token过期,一般要求Client带着ID和Secret再请求一次token。

  • JWT : 全称JSON web token,是一个经过Authorization(Authentication)Server签名的token
  • Asymmetric key : 非对称加密,通过一个公匙和私匙来保证公匙加密的信息只有私匙可以解密

注1:这里要注意JWT加密的并不是payload而是payload的Hash值,以此来确保数据不会在传输中被改动。

注2:选择JWT的原因
  1. JWT + Asymmetric key这样资源服务器不需要存储public key只需要在启动时向Authorization server索取即可
  2. JWT vs Session已经有很多关于此的讨论,这里我们采取用时间(CPU)换空间 (Memory)。值得一提的是Session作为一个广泛应用的技术,有成熟的方案可供参考,建议据自己的需求来选择。JWT有天然的无状态、易于伸缩的优点但是对于token回收以及控制方面有着明显的缺点(在将来的release笔者会重点尝试解决这个问题)。

一些需要注意的地方

  • JWT里有什么?

JWT中的信息并不是加密传输,所以任何敏感信息不可以放在JWT中(当然你也可以添加额外的加密手段)。信息主要包括Client的ID和 权限信息,以及允许访问的资源ID,如果是用户那么用户名称也会被包括,并且用户的权限信息会取代Client的权限信息。

  • 资源服务器是如何被保护?

首先你需要配置资源服务器,添加相关的dependency, 在启动时,服务器会向认证服务器索取public key以用来验证收到的JWT,并根据解码的信息(注意这里并不是解密,因为JWT的payload是base64编码的)来判断是否处理请求。

注:笔者会在之后更新具体的操作方法(添坑)

  • 我应该选择哪个flow ?

如果你是第一方应用那么你并不需要authorization code flow,应用之间通信的话可以采用client credentials flow, 用户登录则采用password flow。如果你是第三方应用那么你只能选择authorization code flow

注:笔者个人认为即使是第一方应用,如果需要获取用户的特定资源还是采取authorization code flow较为合适,这样有利于保持一个较为统一的管理接口,你可以设置为自动批准来提升用户体验(项目目前并不支持自动批准)。


OAuth2应用场景

第三方登录 Authorization code flow

OAuth2的主要应用场景,例如你通过GitHub来登录第三方应用,你授权第三方应用权限来获取你的一些GitHub资源,这样以后再登录(准确来讲是再授权),第三方应用便用这些资源来识别你。在这里第三方应用并不知道你的登录名密码,它只存有你授权获得的资源。

微服务 Client credentials flow或者Password flow

当一个服务被调用时,Authentication和Authorization同样需要。服务需要知道谁在调用,有没有权限调用。这也是笔者学习OAuth2的原因。