微服务架构中的身份验证问题 :JSON Web Tokens( JWT)

2023-11-03

本文翻译自:http://www.svlada.com/jwt-token-authentication-with-spring-boot/

场景介绍

软件安全是一件很负责的问题,由于微服务系统中每个服务都要处理安全问题,所以在微服务场景下会更加复杂,一般我们会四种面向微服务系统的身份验证方案。
在传统的单体架构中,单个服务保存所有的用户数据,可以校验用户,并在认证成功后创建HTTP会话。在微服务架构中,用户是在和服务集合交互,每一个用户都有可能需要知道请求的用户是谁。一种简单的方案是在微服务中,采用与单体系统中相同的模式,但问题是如何让所有的服务访问用户的数据
解决这个问题大致2个思路:(1)使用共享数据库时,更新数据库表会成为一个难题,因为所有的服务必须同时升级以便能够对接修改后的表解构;(2)将相同的数据分发给所有的服务时,当某个用户已经被认证,如何让每个服务都知晓这个状态是个问题。

方案1:单点登录(SSO)方案, 采用单点登录方案,意味着每个面向用户的服务都必须与认证服务交互,这会产生大量非常琐碎的网络流量,同时这个防范实现起来也相当的复杂。在其他方面,选择SSO方案安全性会很好,用户登录状态是不透明的,可防止攻击者从状态中推断任何有用的信息。

方案2:分布式会话方案,原理主要是将关于用户信息存储在共享内存中,并通常由用户会话作为key来实现简单的分布式哈希映射。当用户访问微服务时,用户数据可以从共享存储中获取。该方案的另外一个优点就是用户登录状态不是透明的。当使用分布式数据库时,它也是一个高度可用且可可扩展的解决方案。这种方案的优点是在于共享存储需要一定保护机制,因此需要通过安全链接来访问,这时解决方案的实现就通常具有相当高的负责性了。

方案3:token客户端令牌方案,此令牌在客户端生成,由身份验证服务进行签名,并且必须包含足够的信息,以便可以在所有微服务中建立用户身份。令牌会附加到每一个请求上,为微服务提供身份验证。这种解决方案安全性相对较好,但身份验证注销是一个大大的问题,缓解这种情况的方法可以使用短期令牌access_token 和频繁检查认证服务器等。对于客户端令牌的编码方案,可以使用 JSON Web Tokens( JWT), 它足够简单且支持程度也比较好。

方案4:客户端令牌与API网关结合,这个方案意味着所有的请求都通过网关,从而有效地隐藏了微服务。在请求时,网关将原始用户令牌转换为内部会话(session)ID令牌。在这种情况下,注销就不在是个大大的问题, 因为网关在注销时可以撤销用户的令牌。这种方案虽然支持程度比较好,但是实现起来还是可能相当的复杂。

个人推荐方案:客户端令牌(JWT) + API网关结合的方案,因为这个方案通常使用起来比较容易,且性能也不错。SSO方案虽然能满足需求,但尽量避免使用,若分布式会话方案所需要的相关技术已经应用在你的场景中,那么这个方案也是比较有趣的。在考虑方案的时候,应该考虑注销的重要性。

api网关,参考这篇,
http://geek.csdn.net/news/detail/104715
http://www.dockerinfo.net/773.html

JWT介绍

这篇文章将会知指导你如何用spring boot实现JWT的授权。
文章将会涉及到下面2个方面:
1. Ajax 授权
2. JWT token 授权

前提

请在你细读本篇文章的时候,先看看Github 上的简单项目:https://github.com/svlada/springboot-security-jwt
这个项目是使用H2 内存数据库来存储简单的用户信息。为了让事情变的更加简单,我已经配置了spring boot在自动加载Application自动启动的时候,已经创建了数据设备和配置了spring boot的相关配置(/ jwt-demo / src / main /resources/ data.sql)。

先预览一下下面的项目结构:
+—main
| +—java
| | —com
| | —svlada
| | +—common
| | +—entity
| | +—profile
| | | —endpoint
| | +—security
| | | +—auth
| | | | +—ajax
| | | | —jwt
| | | | +—extractor
| | | | —verifier
| | | +—config
| | | +—endpoint
| | | +—exceptions
| | | —model
| | | —token
| | —user
| | +—repository
| | —service
| —resources
| +—static
| —templates

Ajax 授权

当我们在谈论Ajax授权的时候,我们通常会联想到的是用户是通过JSON 的方式提供凭证,并以XMLHttpRequest 的方式发送的场景。
在本教程的第一部分,Ajax实现身份验证是遵循Spring Security 框架的标准模式。
下面列表的东西,将是要我们去实现的:
1. AjaxLoginProcessingFilter
2. AjaxAuthenticationProvider
3. AjaxAwareAuthenticationSuccessHandler
4. AjaxAwareAuthenticationFailureHandler
5. RestAuthenticationEntryPoint
6. WebSecurityConfig

在我们实现这些细节的时候,让我们细看一下,下面的 request/response 的授权流程。

Ajax 授权请求的例子

身份验证API允许用户传入凭据,来获得身份验证令牌token。
在我们的例子中,客户端启动验证过程通过调用身份验证API(/API/auth/login)。
我们可以写这样的Http 请求:

POST /api/auth/login HTTP/1.1  
Host: localhost:9966  
X-Requested-With: XMLHttpRequest  
Content-Type: application/json  
Cache-Control: no-cache

{
    "username": "svlada@gmail.com",
    "password": "test1234"
}

终端可以用CURL:

curl -X POST -H "X-Requested-With: XMLHttpRequest" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{  
    "username": "svlada@gmail.com",
    "password": "test1234"
}' "http://localhost:9966/api/auth/login"

Ajax 授权相应的例子

如果客户端请求的凭证被通过,授权API将会返回Http响应包括下面的一些细节:

1. Http 状态 "200 OK"
2. 带有 JWT的access_toke 和 refresh_token 都会在 response body中被包含了。

JWT Refresh token

用来获取新的 access_token, 刷新token 可以用这样的API来处理:/api/auth/token.(刷新可以用来防止access_token 的过期)

获取的HTTP 响应格式:

{
  "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMDMzMzA4LCJleHAiOjE0NzIwMzQyMDh9.41rxtplFRw55ffqcw1Fhy2pnxggssdWUU8CDOherC0Kw4sgt3-rw_mPSWSgQgsR0NLndFcMPh7LSQt5mkYqROQ",

  "refreshToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfUkVGUkVTSF9UT0tFTiJdLCJpc3MiOiJodHRwOi8vc3ZsYWRhLmNvbSIsImp0aSI6IjkwYWZlNzhjLTFkMmUtNDg2OS1hNzdlLTFkNzU0YjYwZTBjZSIsImlhdCI6MTQ3MjAzMzMwOCwiZXhwIjoxNDcyMDM2OTA4fQ.SEEG60YRznBB2O7Gn_5X6YbRmyB3ml4hnpSOxqkwQUFtqA6MZo7_n2Am2QhTJBJA1Ygv74F2IxiLv0urxGLQjg"
}

JWT Access Token

JWT访问令牌可用于身份验证和授权:
1. 身份验证是由验证JWT访问令牌签名。如果签名是有效的,访问API请求的资源是理所当然。
2. 授权是通过查找特权JWT scope属性的值来判断。(译者:scope,一般会是版本号或平台,安卓,ios,wap等或不同的系统的id, 具体看自家的场景和需求).

解码JWT token有三个部分:Header(请求头), Claims(要求) and Signature(签名)

Header

{
    "alg": "HS512"
}

Claims(要求):

{
  "sub": "svlada@gmail.com",
  "scopes": [
    "ROLE_ADMIN",
    "ROLE_PREMIUM_MEMBER"
  ],
  "iss": "http://svlada.com",
  "iat": 1472033308,
  "exp": 1472034208
}

签名base64 encoded)

41rxtplFRw55ffqcw1Fhy2pnxggssdWUU8CDOherC0Kw4sgt3-rw_mPSWSgQgsR0NLndFcMPh7LSQt5mkYqROQ  

JWT Refresh Token

Refresh token 是长寿令牌用于请求新的访问令牌。Refresh token过期时间是超过access_token的过期时间。
在本次教程中,我们将使用 jti 声称来维持黑名单,或撤销令牌列表。JWT ID(jti) 声称被 RFC7519 定义了,目的是为了唯一地标识单个刷新令牌。

解码刷新令牌有三个部分: Header(请求头), Claims(要求), Signature(签名) 如下所示:
Header:

{
  "alg": "HS512"
}

Claims:

{
  "sub": "svlada@gmail.com",
  "scopes": [
    "ROLE_REFRESH_TOKEN"
  ],
  "iss": "http://svlada.com",
  "jti": "90afe78c-1d2e-4869-a77e-1d754b60e0ce",
  "iat": 1472033308,
  "exp": 1472036908
}

Signature (base64 encoded)

SEEG60YRznBB2O7Gn_5X6YbRmyB3ml4hnpSOxqkwQUFtqA6MZo7_n2Am2QhTJBJA1Ygv74F2IxiLv0urxGLQjg  

AjaxLoginProcessingFilter( Ajax 登录处理过滤器)

首先,需要继承AbstractAuthenticationProcessingFilter, 目的是为了提供一般常用的Ajax 身份验证请求。反序列化JSON和基本验证的主要任务都是在的。AjaxLoginProcessingFilter#attemptAuthentication这个方法里完成的。在成功验证JSON的主要检验逻辑是委托给AjaxAuthenticationProvider类实现。

在一个成功校验中, AjaxLoginProcessingFilter#successfulAuthentication 方法会被调用。
在一个失败的检验中,AjaxLoginProcessingFilter#unsuccessfulAuthentication 方法被调用。

public class AjaxLoginProcessingFilter</
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微服务架构中的身份验证问题 :JSON Web Tokens( JWT) 的相关文章

随机推荐

  • ETL加载策略

    2019独角兽企业重金招聘Python工程师标准 gt gt gt ETL 数据加载机制概述 ETL 是数据抽取 Extract 转换 Transform 加载 Load 的简写 它的功能是从数据源抽取出所需的数据 经过数据清洗和转换 最终
  • 深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用

    反射的概念 反射 Refelection 反射是Java的特征之一 允许运行中的Java程序获取自身信息 并可以操作类或者对象的内部属性 通过反射 可以在运行时获得程序或者程序中的每一个类型的成员活成成员的信息 程序中的对象一般都是在编译时
  • Echarts实现——中国地图

    Echarts实现 中国地图 如下图 使用Echarts进行地图绘制展示的时候 需要china json 举例在vue的项目中可以通过cnpm install echarts save安装Echarts依赖 引入 import china
  • 1h2g云服务器做网站,云服务器1H2G和1H1G的区别

    云服务器1H2G和1H1G的区别 内容精选 换一换 简要介绍一组Java命令行工具 用于处理高通量排序 HTS 数据和格式 开发语言 Java一句话描述 Java命令行工具开源协议 MIT建议的版本根据实际需要选择版本 本文档以picard
  • Vue——vue3+element plus实现多选表格使用ajax发送id数组

    代码来源 Vue 3结合element plus 问题总结二 之 table组件实现多选和清除选中 在vue3中获取ref 的Dom multipletableref value togglerowselection 打印出来的是u 子时不
  • 设计一个算法将无向图的邻接矩阵转为对应邻接表的算法

    typedef struct int vertex m int edge m m gadjmatrix typedef struct node1 int info int adjvertex struct node1 nextarc gli
  • 通达信软件编程写一段抄底的源代码

    下面是一段基于通达信软件编写的抄底源代码 用于自动识别股票的底部形态并发出买入信号 复制 导入通达信软件自带的股票数据接口 import tdxApi 设置股票代码 周期 数据类型等参数 stockCode 000001 SZ 股票代码 p
  • 使用Mybatis进行更新操作成功,数据库却没更新的原因

    先帖下代码 public void updateCustomerTest throws IOException 1 读取配置文件 String resource mybatis config xml InputStream inputStr
  • Android APK反编译详解(附图)

    这段时间在学Android应用开发 在想既然是用Java开发的应该很好反编译从而得到源代码吧 google了一下 确实很简单 以下是我的实践过程 在此郑重声明 贴出来的目的不是为了去破解人家的软件 完全是一种学习的态度 不过好像通过这种方式
  • 固态硬盘测试软件有哪些,手把手教你测试固态硬盘!硬盘测试软件大汇总

    原标题 手把手教你测试固态硬盘 硬盘测试软件大汇总 如今固态硬盘已经成为了电脑不可或缺的核心配件 装好电脑后 如何快速的通过主流测试软件 检测固态硬盘状态和速度 今天我就和大家聊一聊 有哪些主流的硬盘测试软件 1 CrystalDiskMa
  • python中创建空列表_Python空列表教程–如何在Python中创建空列表

    python中创建空列表 If you want to learn how to create an empty list in Python efficiently then this article is for you 如果您想学习如
  • Java程序员应该知道的10个调试技巧

    Java程序员应该知道的10个调试技巧 发表于 18小时前 231次阅读 来源 javapapers 1 条评论 作者 Joe Eclipse Java 研发实践 Bug 摘要 调试不仅可以查找到应用程序缺陷所在 还可以解决缺陷 对于Jav
  • PHP PSR-2 代码风格规范

    代码风格规范 本篇规范是 PSR 1 基本代码规范的继承与扩展 本规范希望通过制定一系列规范化PHP代码的规则 以减少在浏览不同作者的代码时 因代码风格的不同而造成不便 当多名程序员在多个项目中合作时 就需要一个共同的编码规范 而本文中的风
  • ROS学习——读取激光雷达数据Laser

    在ROS工作空间的src文件夹下创建read laser功能包 并在包内创建include launch src四个文件夹 在include文件夹中创建read laser h文件 并写入以下内容 include
  • 【opencv实践】深入理解回调函数

    前言 学弟学妹们开始学opencv了 参看的书籍是毛星云的 oepncv3编程入门 编程环境是用的VS2017或VS2019 该项目是给他们留的第一次作业 作业内容 读取一张图片 在该图片上截取一个ROI区域 将截取的图片在一个新的窗口内展
  • uni-app 如何设置 怎么设置 input textarea设置只读 readonly

    uni app input 设置只读 设置属性disabled为true或disabled
  • Vue获取实时时间

    html代码 div nowDate nowTime div js代码 created this timer setInterval this getTime 1000 beforeDestroy if this timer clearIn
  • Java字符串String类型简述

    String是Java库中预定义的类 属于引用类型 使用它的变量称为引用变量 用于引用对象 目录 声明 求字符串长度 从字符串中获取字符 从字符串中查找字符 从字符串中获得子串 从字符串中查找子串 连接字符串 字符串的大小写转换 字符串与数
  • openssl enc 加密/解密文件

    OpenSSL 可用密码或者秘钥方式进行加密 近期用到用密码进行加密解密 故记录之 AES256 是对称加密的一种 可参考相关博客 加密 openssl enc e openssl enc e aes256 pbkdf2 iter INT
  • 微服务架构中的身份验证问题 :JSON Web Tokens( JWT)

    本文翻译自 http www svlada com jwt token authentication with spring boot 场景介绍 软件安全是一件很负责的问题 由于微服务系统中每个服务都要处理安全问题 所以在微服务场景下会更加