当前位置: 首页 > 工具软件 > Zhihu-OAuth > 使用案例 >

Spring security + Oauth2 + Jwt认证鉴权方案

袁耀
2023-12-01

基础概念

  • 用户身份认证

    用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问。常见的用户身份认证表现形式有:用户名密码登录,指纹打卡等方式

  • 用户授权

    用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问

  • 五种认证机制

    1. HTTP Basic Auth
      HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth

    2. OAuth
      OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容

    3. Cookie-session Auth
      Cookie-session 认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效;
      但是这种基于cookie-session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来。

    4. Token Auth
      基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

    5. JWT Auth
      Token Auth的进化版本。由于Token Auth不包含用户信息,无法确定用户的请求的访问权限范围,即可以访问哪些数据。JWT作为一种可以转载数据的token,可以把用户权限信息放入token中,服务端不必再保存用户和权限的状态信息。
      适用于分布式服务。

  • 用户身份认证

    用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问。常见的用户身份认证表现形式有:用户名密码登录,指纹打卡等方式

  • http 3xx 重定向状态码
    重定向状态码用来告诉浏览器客户端,它们访问的资源已被移动, Web服务器发送一个重定向状态码, 告诉客户端新的资源地址在哪。浏览器客户端会根据提供的地址,重新发送新的Request。

    301表示资源不在旧位置,永久移动到新位置。新位置的URL信息在response中的Location中;302同301类似,区别在于目标资源只是临时移动到新位置;

    浏览器在获取到302的响应值后,会拿到响应头中的Location中的URL,并跳转到该URL

业务场景

  • 登录
    用户登录系统,请求各种资源。

  • 单点登录(Single Sign On)
    简称为 SSO,用于企业业务整合的解决方案之一,是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统

  • 第三方认证

    当需要访问第三方系统的资源时需要首先通过第三方系统的认证(例如:微信认证),由第三方系统对s用户认证通过,并授权资源的访问权限(一般访问用户信息)。

OAuth2

OAuth2 认证的好处就是你只需要一个账号密码,就能在各个网站进行访问,而面去了在每个网站都进行注册的繁琐过程,如:很多网站都可以使用微信登录,网站作为第三方服务、微信作为服务提供商。

OAuth2是一个关于授权的开放标准,核心思路是通过各类认证手段(具体什么手段OAuth2不关心)认证用户身份,并颁发token(令牌),使得第三方应用可以使用该令牌在限定时间限定范围访问指定资源。

假设张三使用微信登录微博的场景 ,

  • 张三是一个微信用户,那么微信资源服务器(此处是存储用户信息的服务器)中就保存了张三的用户信息(张三在注册微信时录入的内容),此时微信资源服务器中张三的用户信息就是一种资源,且该资源的拥有者是张三。
  • 有一天,张三第一次访问微博(微博是第三方应用,且微博这个应用已经在微信授权服务器(不是资源服务器)中获得了一个唯一标识),微博要求张三注册账号并输入用户信息。
  • 由于这些用户信息同微信服务器中的用户信息十分类似,微博提供使用微信账号登录的方式来登录微博,用户只需做一下授权就可以直接登录微博,不用再输入用户信息。
  • 用户信息由微博后台从微信资源服务器中获取,这个获取用户信息的过程就是Oauth2的工作过程。

上面过程的最后一步的概要目标是,微博后台想要拿到微信服务器中张三的用户信息,首先需要获得张三的授权(一般是弹出页面点击同意即可),然后微信授权服务器会给微博后台发放一个access_token,微博后台拿着这个access_token就可以去访问微信资源服务器中的张三用户信息。

特别强调的是,此处的授权指的是 在用户的参与下,一个授权服务器(管理一堆资源服务)给另一个应用(第三方应用)颁发一个访问令牌,颗粒度比较大,是应用或服务级的授权。

四种客户端授权方式

OAuth2一般多采用授权码方式,完成两个服务之间的授权。此处

  • 授权码模式(authorization code) 参考资料
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

spring security

spring security是一个安全管理框架,主要核心功能

  • 认证(Authentication):指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。
  • 授权(Authorization):指的是验证某个用户是否有权限执行某个操作

其核心就是一组过滤器链,添加依赖之后,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。

spring security和shiro都是安全管理框架,后者使用简单功能稍弱,一般和ssm配合构建项目。 spring security功能强大,但是操作复杂,一般配合springboot/cloud(自动化配置)一起使用。

特别强调的是,spring security侧重用户和系统之间的请求管理,即某一个用户是否可以访问系统,可以访问系统哪些资源。

JWT

有了 OAuth2和spring security 就可以一个安全管理框架,其操作流程如下

  1. 用户首次访问资源服务器时,资源服务器会将该请求转发到授权服务器
  2. 授权服务器会拦截请求并返回用户一个token ,同时授权服务器将该token和用户的对应信息存储在授权服务器的session中
  3. 浏览器将token存储在本地的cookie中,下一次访问资源服务器携带该token
  4. 此时用户虽然是非首次访问,但仍旧需要先在授权服务器上认证授权,然后才能去访问资源服务器。

问题出来第4步,普通的oauth2颁发的就是一串随机hash字符串,本身无意义。OAuth2的token技术最大的问题是不携带用户信息,且资源服务器无法进行本地验证,每次对于资源的访问,资源服务器都需要向认证服务器发起请求,一是验证token的有效性,二是获取token对应的用户信息。如果有大量的此类请求,无疑处理效率是很低的,且认证服务器会变成一个中心节点,对于SLA和处理性能等均有很高的要求,这在分布式架构下是很要命的。

JWT就是在这样的背景下诞生的,从本质上来说,jwt就是一种特殊格式的token。而jwt格式的token是有特定含义的,它包含了yoghurt信息,分为三部分:

  • 头部Header
  • 载荷Payload
  • 签名Signature

这三部分均用base64进行编码,当中用.进行分隔,一个典型的jwt格式的token类似xxxxx.yyyyy.zzzzz

认证服务器通过对称或非对称的加密方式利用payload生成signature,并在header中申明签名方式,仅此而已。通过这种本质上极其传统的方式,jwt可以实现分布式的token验证功能,即资源服务器通过事先维护好的对称或者非对称密钥(非对称的话就是认证服务器提供的公钥),直接在本地验证token,这种去中心化的验证机制无疑很对现在分布式架构的胃口。jwt相对于传统的token来说,解决以下两个痛点:

  • 通过验证签名,token的验证可以直接在本地完成,不需要连接认证服务器
  • 在payload中可以定义用户相关信息,这样就轻松实现了token和用户信息的绑定

在上面的那个资源服务器和认证服务器分离的例子中,如果认证服务器颁发的是jwt格式的token,那么资源服务器就可以直接自己验证token的有效性并绑定用户,这无疑大大提升了处理效率且减少了单点隐患。

Oauth2 和 spring security 和 Jwt

  • Oauth2是一个标准,即是一个理论,独立无法完成认证和鉴权
  • spring security 是一个框架,它实现了Oauth2,可以基于普通token(随机hash字符串,本身无意义)实现认证和鉴权。
  • jwt是可以包含用户信息的token,Spring security + Oauth2 + Jwt认证鉴权方案可以解决分布式环境下 Spring security + Oauth2方案导致的认证服务器请求多的问题,实现了分布式权限认证。

参考资料

 类似资料: