技术方案之CAS认证
概述
CAS 是耶鲁大学的开源项目,宗旨是为 web 应用系统提供一种可靠的单点登录解决方案。
CAS 从安全性角度来考虑设计,用户在 CAS 输入用户名和密码之后通过ticket进行认证,能够有效防止密码泄露。 CAS 广泛使用于传统应用场景中,比如企业内部的 OA ,ERP等应用,不适用于微服务领域。

设计实现流程
-
用户尝试访问应用:
- 用户首次尝试访问一个受 CAS 保护的应用程序。
- 如果用户未被认证,应用程序会重定向用户到 CAS 服务器的登录页面。
-
用户在 CAS 服务器上进行认证:
- 用户在 CAS 服务器提供的登录页面上输入用户名和密码。
- CAS 服务器验证用户的凭证。如果验证成功,CAS 服务器会创建一个票据授予票据(Ticket Granting Ticket, TGT)并将其与用户会话关联起来。
-
CAS 服务器生成服务票据:
- 应用程序再次请求 CAS 服务器,这次是请求一个服务票据(Service Ticket, ST)。这个请求包含一个特定的服务标识符。
- CAS 服务器生成一个 ST,并将它与 TGT 关联起来。ST 是一次性使用的票据,用于后续的认证过程。
-
应用程序验证服务票据:
- 应用程序接收到 ST 后,向 CAS 服务器发送一个验证请求,包含 ST 和服务标识符。
- CAS 服务器验证 ST 的有效性。如果验证成功,CAS 服务器返回用户的身份信息给应用程序。
-
应用程序建立会话:
- 应用程序根据 CAS 服务器返回的身份信息为用户创建本地会话。(session)
- 用户现在可以访问该应用程序,而无需再次进行身份验证。(sessionID)
-
用户访问其他应用:
- 当用户尝试访问另一个同样受 CAS 保护的应用程序时,重复上述过程。
- 由于用户已经在 CAS 服务器上进行了认证,因此不需要再次输入凭证,可以直接获得 ST 并通过验证。

以上就是我们CAS认证的全流程,接下来我们再看看实际应用中的两一个问题,代理访问认证是如何做到的
CAS****代理认证
什么是代理认证?
有两个应用App1 和 App2 ,它们都是受 Cas Server 保护,请求它们时都需要通过 Cas Server 的认证。现需要在App1 中以 Http 方式请求访问 App2 ,显然该请求将会被 App2 配置的 Cas 的
AuthenticationFilter 拦截并转向 Cas Server , Cas Server 将引导用户进行登录认证,这样我们也
就不能真正的访问到 App2 了。针对这种应用场景, Cas 也提供了对应的支持。
代理认证具体流程
App1 先通过 Cas Server 的认证,然后向 Cas Server 申请一个针对于 App2 的 proxy ticket ,之后在
访问 App2 时把申请到的针对于 App2 的 proxy ticket 以参数 ticket 传递过去。 App2 的
AuthenticationFilter 将拦截到该请求,发现该请求携带了 ticket 参数后将放行交由后续的
Ticket Validation Filter 处理。 Ticket Validation Filter 将会传递该 ticket 到 Cas Server 进行认证,显
然该 ticket 是由 Cas Server 针对于 App2 发行的, App2 在申请校验时是可以校验通过的,这样我们
就可以正常的访问 App2 了。
-
客户端应用作为代理:
- 假设客户端应用需要访问另一个受 CAS 保护的目标服务。
- 客户端应用首先需要从 CAS 服务器获取一个代理票据授予票据(Proxy Granting Ticket, PGT)。
- 客户端应用通过发送一个特殊的 URL 请求到 CAS 服务器来获取 PGT。这个 URL 包含了一个回调 URL,CAS 服务器会在生成 PGT 后调用这个回调 URL,并将 PGT 传递给客户端应用。
-
客户端应用获取代理票据:
- 客户端应用使用 PGT 向 CAS 服务器请求一个代理票据(Proxy Ticket, PT)。
- CAS 服务器生成一个 PT,并将其与 PGT 关联起来。PT 也是一次性使用的票据,用于目标服务的认证。
-
客户端应用访问目标服务:
- 客户端应用将 PT 附加到请求中,然后访问目标服务。
- 目标服务接收到请求后,向 CAS 服务器发送一个验证请求,包含 PT 和服务标识符。
- CAS 服务器验证 PT 的有效性。如果验证成功,CAS 服务器返回用户的身份信息给目标服务。
-
目标服务处理请求:
- 目标服务根据 CAS 服务器返回的身份信息处理客户端应用的请求。
- 目标服务可以信任客户端应用传递过来的用户身份信息,并根据这些信息决定用户是否有权访问请求的资源。

技术方案之OpenID认证
概述
OIDC( OpenID Connect) 是属于是 OAuth 2.0 协议之上的简单身份层,用 API 进行身份交互,允许
客户端根据授权服务的认证结果确认用户的最终身份,它支持包括 Web 、移动、 JavaScript 在内的
所有客户端类型。
它与 OAuth 的主要区别是在于 , OpenID 只用于身份认证,例如允许一个账户登录多个网站;而OAuth可以用于授权,允许授权的客户端访问指定的资源服务。
应用场景
如果有独立账号体系,需要为外部提供统一认证服务,可以采用OIDC , OIDC 目前有很多企业在
使用,比如Google的账号认证体系, Microsoft 的账号体系也采用了 OIDC 。
如何工作
OAuth2 提供了 Access Token 来解决授权第三方客户端访问受保护资源的问题; OIDC 在这个基础
上提供了 ID Token 来解决第三方客户端标识用户身份认证的问题。 OIDC 的核心在于在 OAuth2 的授
权流程中,一并提供用户的身份认证信息( ID Token )给到第三方客户端, ID Token 使用 JWT 格式
来包装,得益于 JWT ( JSON Web Token )的自包含性,紧凑性以及防篡改机制,使得 ID Token 可
以安全的传递给第三方客户端程序并且容易被验证。此外还提供了 UserInfo 的接口,用户获取用
户的更完整的信息。
工作流程
术语解析 :
-
- EU(End User):代表终端用户。
-
- RP(Relying Party): 指OAuth2中受信任的客户端。
-
- OP(OpenID Provider):有能力提供EU认证的服务(比如OAuth2中的授权服务),为RP提供EU的身份认证信息.
-
- ID Token:JWT格式的数据,包含EU身份认证的信息。
-
- UserInfo Endpoint:用户信息接口(受OAuth2保护),当RP使用Access Token访问时,返 回授权用户的信息,此接口必须使用HTTPS。

工作模式
- 默认模式 / 简化模式( Implicit Flow ):
如果是Web 应用服务,其所有的代码都有可能被加载到浏览器暴露出来,无法保证终端client_secret 的安全性,则采用默认模式。 - 授权码模式( Authentication Flow ):
如果是传统的客户端应用,后端服务和用户信息是隔离的,能保证client_secret 的不被泄露,就可以使用授权码模式流程。 - 混合模式( Hybrid Flow ):
实质上是以上两种模式的融合,混合模式下ID Token 通过浏览器的前端通道传递,而Access Token 和 Refresh Token 通过后端获取,混合使用,可以弥补两种模式的缺点,一般推荐使用混合模式。
技术方案之SAML2.0认证(重点)
概述
- SAML 2.0 用来在安全域中交换身份验证(Authentication)数据和 授权(Authorization)数据。
- SAML 2.0基于XML协议,使用包含断言(Assertions)的安全令牌在SAML授权方(即身份提供者IdP)和SAML消费方(即服务提供者SP)之间传递委托人(终端用户)的信息。
- SAML 2.0 可以实现基于网络跨域的单点登录(SSO),以便于减少向一个用户分发多个身份验证令牌的管理开销。
我们来举个简单的例子说明SAML认证的过程
假设你是一家大公司的员工,公司内部有多个不同的应用系统,比如电子邮件系统、项目管理系统和人力资源系统。每个系统都由不同的部门维护,但你希望只用一组用户名和密码就能访问所有这些系统,而不需要为每个系统单独登录。
那么在SAML里面有两种角色
- 身份提供者 (IdP): 公司的统一认证服务,负责验证用户的身份。
- 服务提供者 (SP): 各个应用系统,如电子邮件系统、项目管理系统和人力资源系统。
其认证过程如下:
-
用户尝试访问应用:
- 你打开浏览器,尝试访问公司的电子邮件系统(SP)。
- 由于你还没有登录,电子邮件系统会重定向你到公司的统一认证服务(IdP)。
-
用户在 IdP 上进行认证:
- 你在 IdP 的登录页面输入你的用户名和密码。
- IdP 验证你的凭证。如果验证成功,IdP 会生成一个 SAML 断言(Assertion),其中包含你的身份信息(如用户名、角色等)。
-
SAML 断言的生成:
- SAML 断言是一个 XML 文档,包含以下信息:
Subject:标识用户的信息,通常包括用户的唯一标识符。Conditions:断言的有效期和其他条件。Authentication Statement:关于用户如何被认证的信息(如认证时间、认证方法等)。Attribute Statement:用户的属性信息,如角色、权限等。
- SAML 断言是一个 XML 文档,包含以下信息:
-
重定向回 SP 并传递 SAML 断言:
- IdP 将 SAML 断言加密并封装在一个 SAML 响应中。
- IdP 重定向你回到电子邮件系统的登录 URL,并附带 SAML 响应。这个过程通常是通过 HTTP POST 请求完成的,以确保数据的安全性。
-
SP 验证 SAML 断言:
- 电子邮件系统接收到 SAML 响应后,解密并验证 SAML 断言。
- 电子邮件系统检查断言中的签名,确保它来自可信的 IdP。
- 电子邮件系统还检查断言的有效期和其他条件,确保断言是有效的。
-
创建本地会话:
- 如果 SAML 断言验证成功,电子邮件系统会根据断言中的信息创建一个本地会话。
- 你现在可以访问电子邮件系统,而无需再次输入用户名和密码。
-
用户访问其他 SP:
- 当你尝试访问公司的其他应用系统(如项目管理系统或人力资源系统)时,重复上述过程。
- 由于你已经在 IdP 上进行了认证,因此不需要再次输入凭证,可以直接通过 SAML 断言进行认证。
接下来我们详细看一下其中的细节部分
什么是断言
断言是一个包含了由 SAML 授权方提供的 0 到多个声明( statement )的信息包。 SAML 断言通常围绕一个主题生成。该主题使用声明。
SAML 2.0 规范定义了三种断言声明,详细信息如下:
- 身份验证(Authentication):该断言的主题是在某个时间通过某种方式被认证。
- 属性(Attribute):该断言的主题和某种属性相关联。
- 授权决策(Authorization Decision):该断言的主题被允许或者被禁止访问某个资源。
比如:
XML
<!-- SAML断言的根元素,包含了断言的所有信息 -->
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
ID="b07b804c-7c29-ea16-7300-4f3d6f7928ac"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<!-- 发行者元素,标识了断言的发行实体 -->
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- 数字签名元素,用于验证断言的完整性和发行者的身份 -->
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- 签名内容 -->
</ds:Signature>
<!-- 主体元素,包含了与用户身份相关的信息 -->
<saml:Subject>
<!-- 名称ID元素,提供了用户的唯一标识符 -->
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
3f7b3dcf-1674-4ecd-92c8-1544f346baf8
</saml:NameID>
<!-- 主体确认元素,提供了断言的接收方用来验证主体身份的信息 -->
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="aaf23196-1773-2113-474a-fe114412ab72"
Recipient="https://sp.example.com/SAML2/SSO/POST"
NotOnOrAfter="2004-12-05T09:27:05Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<!-- 条件元素,定义了断言的有效条件 -->
<saml:Conditions NotBefore="2004-12-05T09:17:05Z" NotOnOrAfter="2004-12-05T09:27:05Z">
<!-- 受众限制元素,定义了断言的目标受众 -->
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/SAML2</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<!-- 认证声明元素,提供了用户认证的信息 -->
<saml:AuthnStatement AuthnInstant="2004-12-05T09:22:00Z" SessionIndex="b07b804c-7c29-ea16-7300-4f3d6f7928ac">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<!-- 属性声明元素,提供了关于用户的属性信息 -->
<saml:AttributeStatement>
<saml:Attribute xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
x500:Encoding="LDAP"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
FriendlyName="eduPersonAffiliation">
<saml:AttributeValue xsi:type="xs:string">member</saml:AttributeValue>
<saml:AttributeValue xsi:type="xs:string">staff</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
它主要是用来实现 Web 浏览器的单点登录。
该断言包括一个身份验证断言 saml:AuthnStatement 和一个属性断言 saml:AttributeStatement , SP 将使用该属性断言实现访问控制。
工作流程
SAML 认证流程一般都会牵涉到两方:服务提供方( SP )和身份提供方( IdP ),典型的 SP 有阿里云、腾讯云以及很多很多的 SaaS 服务; IdP 其实就是我们企业自己,因为用户目录在我们这里。
访问 SP 服务的时候, SP 会向 IdP 发送一个 SAML Request (具体是什么我们暂时不关心),请求 IdP判断用户身份。IdP 收到 SAML Request 后,可以通过某种手段对用户身份进行认证,如果已登录,可以直接返回用户身份信息给 SP ;如果未登录,可以弹出一个登录框,用户登录之后再将用户身份返回给 SP 。 SP 收到用户信息之后,再在自己的数据库里面找出对应的用户,然后以这个用户的身份访问 SP服务。

-
- 用户通过浏览器访问网站(SP),网站提供服务但是并不负责用户认证。
-
- SP 向 IDP 发送了一个 SAML 认证请求,同时 SP 将 用户浏览器 重定向到 IDP。
-
- IDP 在验证完来自 SP 的合法请求, 在浏览器中呈现登陆表单让用户填写用户名与密码信息,进行登陆。
-
- 用户登陆成功, IDP 会生成一个包含用户信息的 SAML token(SAML token 又称为 SAML Assertion,本质上是 XML 节点)。IDP 向 SP 返回 token,并且将 用户重定向 到 SP。
-
- SP 对拿到的 token 进行验证,并从中解析出用户信息,例如用户是谁以及用户的权限有哪些。此时可以根据这些授权信息允许用户访问我们网站的内容。
AWS云服务接入介绍
用户池进行身份验证

用户使用用户池进行身份验证。应用程序用户可以通过用户池直接登录,也可以通过第三方身份提
供商 (IdP) 联合。用户池管理从通过 Facebook、Google、Amazon 和 Apple 进行的社交登录返回
的以及从 OpenID Connect (OIDC) 和 SAML IdP 返回的令牌的处理开销。
成功进行身份验证后, Web 或移动应用程序将收到来自 Amazon Cognito 的用户池令牌。可以使用这些令牌检索允许的应用程序访问其他 AWS 服务的 AWS 凭证,也可以选择使用它们来控制对您的服务器端资源或 Amazon API Gateway 的访问。
用户池访问服务器端资源

用户池登录后,Web 或移动应用程序将收到用户池令牌。可以使用这些令牌控制对服务器端资源
的访问。可以创建用户池组来管理权限以及表示不同类型的用户。
用户池和身份池访问云服务
用户池登录认证成功之后,获取返回的令牌,再通过令牌换取身份池的信息,拿去身份池信息就可以访问其他的云服务资源。

阿里云接入方案介绍
阿里云提供以下两种基于SAML 2.0协议的SSO方式:
用户SSO:
- 阿里云通过IdP颁发的SAML断言确定企业用户与阿里云RAM用户的对应关系 。企业用户登录后,使用该RAM用户访问阿里云。
角色SSO:
- 阿里云通过IdP颁发的SAML断言确定企业用户在阿里云上可以使用的RAM角色。企业用户登录后,使用SAML断言中指定的RAM角色访问阿里云。请参见进行角色SSO。
用户****SSO

当管理员在完成用户SSO的相关配置后,可以通过以下流程来实现用户SSO。
-
- Alice使用浏览器登录阿里云,阿里云将SAML认证请求返回给浏览器。
-
- 浏览器向IdP转发SAML认证请求。
-
- IdP提示Alice登录,并在Alice登录成功后生成SAML响应返回给浏览器。
-
- 浏览器将SAML响应转发给SSO服务。
-
- SSO服务通过SAML互信配置,验证SAML响应的数字签名来判断SAML断言的真伪,并通过SAML断言的NameID元素值,匹配到对应阿里云账号中的RAM用户身份。
-
- SSO服务向浏览器返回控制台的URL。
-
- 浏览器重定向到阿里云控制台。
角色SSO

-
- 企业员工Alice可登录到阿里云,使用浏览器在IdP的登录页面中选择阿里云作为目标服务。
-
- IdP生成一个SAML响应并返回给浏览器。
-
- 浏览器重定向到SSO服务页面,并转发SAML响应给SSO服务。
-
- SSO服务使用SAML响应向阿里云STS服务请求临时安全凭证,并生成一个可以使用临时安全凭证登录阿里云控制台的URL。
-
- SSO服务将URL返回给浏览器。
-
- 浏览器重定向到该URL,以指定角色身份登录到阿里云控制台。
技术方案之OAuth2.0认证(重点)
概述
OAuth2 实质是为第三方应用颁发一个具有时效性的Token令牌,使其他服务或第三方应用能够通过令牌获取相关资源。
常见的场景: 比如进入某个网站没有账号信息, 但可以通过QQ、微信、支付宝等账号进行登陆, 在这个登陆过程中采用的就是Oauth2协议;OAUTH2不仅支持认证,还具备授权功能,比如通过QQ登录获取用户头像,基本资料等。
OAuth2****角色
- resource owner : 资源所有者,具备访问该资源的实体,如果是某个人,被称为end-user。
- resources server: 资源服务器,受保护的资源服务器, 具备提供资源能力, 如订单服务, 商品服务等。
- client: 客户端,这并不是指用户, 而是对资源服务器发起请求的应用程序,比如前后分离项目,前端服务访问管理接口, 访问后台业务功能接口。
- authorization server: 授权服务器, 能够给客户端颁发令牌, 这个就是我们上面所讲的统一认证授权服务器。
- user-agent: 用户代理, 作为资源所有者与客户端沟通的工具, 比如APP, 浏览器等。
OAuth2****协议流程

-
- Resource Owner 与 Client 之间 , 资源所有者向Client发起认证请求, Client再返回认证授权信息。
-
- Client 收到 Resource Owner 的认证请求后,会去Authorization Server 申请访问令牌,Authorization Server会让Client 进行认证,通过之后会返回Access Token。
-
- Client 拿到 Authorization Server 的 Acceess Token , 访问Resource Server,Resource Server验证之后, 返回被保护的资源信息。
-
- Resource Server 可以通过JWT在本地进行验证, 也可以访问 Authorization Server, 对Client 的请求的合法性进行验证。
OAuth2四种授权模式
授权码模式

-
- 客户端携带 client_id, scope, redirect_uri, state 等信息引导用户请求授权服务器的授权端点下发code。
-
- 授权服务器验证客户端身份,验证通过则询问用户是否同意授权(此时会跳转到用户能够直观看到的授权页面,等待用户点击确认授权)。
-
- 假设用户同意授权,此时授权服务器会将 code 和 state(如果客户端传递了该参数)拼接在 redirect_uri 后面,以302(重定向)形式下发 code。
-
- 客户端携带 code, redirect_uri, 以及 client_secret 请求授权服务器的令牌端点下发 access_token。
-
- 授权服务器验证客户端身份,同时验证 code,以及 redirect_uri 是否与请求 code 时相同,验证通过后下发 access_token,并选择性下发 refresh_token,支持令牌的刷新。
示例:
- 授权请求:
java
response_type=code // 必选项
&client_id={客户端的ID} // 必选项
&redirect_uri={重定向URI} // 可选项
&scope={申请的权限范围} // 可选项
&state={任意值} // 可选项
- 授权响应参数:
java
code={授权码} // 必填
&state={任意文字} // 如果授权请求中包含 state的话那就是必填
- 令牌请求:
java
grant_type=authorization_code // 必填
&code={授权码} // 必填 必须是认证服务器响应给的授权码
&redirect_uri={重定向URI} // 如果授权请求中包含 redirect_uri 那就是必填
&code_verifier={验证码} // 如果授权请求中包含 code_challenge 那就是必填
- 令牌响应:
java
"access_token":"{访问令牌}", // 必填
"token_type":"{令牌类型}", // 必填
"expires_in":{过期时间}, // 任意
"refresh_token":"{刷新令牌}", // 任意
"scope":"{授权范围}" // 如果请求和响应的授权范围不一致就必填
隐式**/**简化模式

-
资源拥有者(用户)通过代理(WEB浏览器)访问客户端程序,发起简化模式认证。
-
客户端(Client)向认证服务器(Auth Server)发起请求, 此时客户端携带了客户端标识
(client_id)和重定向地址(redirect_uri)。
- 客户端(Client)拿到令牌 token 后就可以向第三方的资源服务器请求资源了
示例 : - 授权请求:
bash
response_type=token // 必选项
&client_id={客户端的ID} // 必选项
&redirect_uri={重定向URI} // 可选项
&scope={申请的权限范围} // 可选项
&state={任意值} // 可选项
- 授权响应参数:
bash
&access_token={令牌信息} // 必填
&expires_in={过期时间} // 任意
&state={任意文字} // 如果授权请求中包含 state 那就是必填
&scope={授权范围} // 如果请求和响应的授权范围不一致就必填
思考:为什么要有授权码和简化模式?看完这两种模式, 可能会有些疑问, 为什么要这么麻烦, 直接一次请求返回TOKEN不就可以吗?
我们可以看出, 两者主要差别, 是少了code验证环节, 直接返回token了, code验证是客户端与认证服务器在后台进行请求获取, 客户端是后端(专门去和认证服务器做交互的),不是浏览器。所以token不会在浏览器暴露,浏览器只拥有code
密码模式
- 资源拥有者直接通过客户端发起认证请求。
- 客户端提供用户名和密码, 向认证服务器发起请求认证。
- 认证服务器通过之后, 客户端(Client)拿到令牌 token 后就可以向第三方的资源服务器请求资源了。
此模式简化相关步骤, 直接通过用户和密码等隐私信息进行请求认证, 认证服务器直接返回token,这需要整个环境具有较高的安全性。
客户端模式
- 此模式最为简单直接, 由客户端直接发起请求。
- 客户端与服务器信赖度较高, 服务端根据请求直接认证返回token信息。
- 客户端(Client)拿到令牌 token 后就可以向第三方的资源服务器请求资源了。
这种模式一般在内部服务之间应用, 授权一次, 长期可用, 不用刷新token。
OAuth认证的实际技术方案
增强Token技术解决方案

基于Token的鉴权方案,实现方式有多种,增强Token属于其中一种,为什么要采用增强Token方式,它能够解决怎样的问题?
普通Token认证方式,没有附带必要的用户信息,如果要查询,需要再次调用OAuth2的用户资料认证接口,会增加传输开销;JWT虽然能够附带一定用户信息,但受限于长度,存储空间有限; 如果既要保障性能,又要求能够存储一定的信息,就可以采用增强Token方案,它是将信息存储至Redis缓存中,作为资源服务,接收到Token之后, 可以直接从Redis中获取信息。
它可以适用于微服务架构下,有一定用户信息要求的场景,比如订单服务、资金服务需要获取用户的基本资料,但如果是跨IDC,跨区域,需要暴露外网的情况下,不推荐采用此方案,因为需要保障数据的安全性。
JWT****技术解决方案
jwt其实就是一串特殊的token,内容上存储了一些用户认证信息,但是加密了的
JWT认证流程:

JWT缺陷:
-
- 更多的空间占用。如果将存在服务端session中的各类信息都放在JWT中保存在客户端,可能造成JWT占用更大空间,需要考虑cookie的空间限制因素,如果放在Local Storage,则可能受到XSS攻击。
-
- 更不安全。这里是特指将JWT保存在Local Storage中,然后使用Javascript取出后作为HTTP header发送给服务端的方案。在Local Storage中保存敏感信息并不安全,容易受到跨站脚本攻击,跨站脚本(Cross site script,简称xss)是一种"HTML注入",由于攻击的脚本多数时候是跨域的,所以称之为"跨域脚本",这些脚本代码可以盗取cookie或是Local Storage中的数据( XSS攻 击的原理解释)。
-
- 无法作废已颁布的令牌。所有的认证信息都在JWT中,由于在服务端是无状态,即使你知道了某个JWT被盗取了,也没有办法将其作废。在JWT过期之前,除非主动增加过期接口,否则无法处理。
-
- 续签问题。传统 session请求时是可以自动续期,payload之中有一个exp过期时间参数,它可以代表JWT的时效性,但JWT自身设计并没有考虑续签问题,因为payload是参与签名处理,如果exp过期时间被修改,那整个JWT串就会产生变化,所以JWT原生并不支持续签。
JWT 应用优化方案 :
- 针对安全性问题:
可以使用Cookie 存储,并设置HttpOnly=true ,只能由服务端保存以及通过自动回传的cookie 取得 JWT ,以便防御 XSS 攻击;在JWT 载体中加入一个随机值作为 CSRF 令牌,服务端将令牌也保存在Cookie 中,前端可以取得该令牌并在请求时作为 HTTP header 头部信息传递,服务端在认证时,从JWT 取出 CSRF 令牌和 HEADER 中的令牌做比对,从而防止 CSRF 的攻击。 - 续签问题:
通过Token 的 Refresh 机制来实现,需要对 JWT 的传递做统一封装,客户端再开辟一个
线程定期检测有效期,临近过期时重新刷新 Tokens ,进行全局更新。