项目经验分享:在 JustAuth Plus 中添加 HTTP API 的登陆方式
# 项目综述
什么是 JustAuth Plus(JAP),它有什么用?JustAuth Plus 衍生于 JustAuth (opens new window) 项目。JustAuth 是一个第三方授权登录的工具类库,它集成了国内外多家知名的第三方平台。JustAuth Plus 是在 JustAuth 的基础上进行开发的,是一款开源的登录认证中间件,基于模块化设计,为所有需要登录认证的 WEB 应用提供一套标准的技术解决方案,开发者可以基于 JAP 适配绝大多数的 WEB 系统(自有系统、联邦协议),就像集成 JustAuth 一样,简单方便。假如你想查看更多关于 JustAuth Plus 的信息可以点击进入其官网:https://justauth.plus/。
JustAuth Plus 目前支持多种认证登陆方式,例如 Oauth2.0、OIDC、账号密码等方式,但是还不支持通过 HTTP API 接口的形式进行登陆验证。本次的项目需求就是为 JustAuth Plus 编写 HTTP API 模块。
# 需求分析
在 “以 HTTP API 接口形式进行登陆验证的过程” 中,存在三个主体:
- 业务系统(开发者系统)
- 第三方系统(身份服务提供商)
- 用户
用户在登陆业务系统时,会向业务系统提供用户的认证信息。业务系统通过 HTTP API 接口向第三方系统发送认证请求,以此来进行用户信息的认证鉴权。示意图如下:
对于开发业务系统的开发者而言,业务系统中可能需要集成多个第三方系统,各个系统对外暴露的 HTTP API 的协议规范可能有所不同。因此在业务系统中集成第三方系统变为了一件棘手的事情。
在此次的项目开发中,我需要做的就是添加 JAP 中 HTTP API 模块,开发者在简单配置该模块之后就能很轻松地在其业务系统中集成第三方系统的登陆认证功能。
# 模块难点
在没有使用本模块的情况下,第三方系统向外暴露 HTTP API 接口,开发者向其发送鉴权请求时需要遵守 HTTP 认证鉴权协议。本模块需要为开发者屏蔽 HTTP 认证鉴权协议上的细节,这就是开发本模块的难点所在。
在查阅了许多资料文档(参见文末参考文献),深入学习了 HTTP 认证鉴权之后,总结出了 HTTP 认证的三大方式:
1、BASIC 认证
Basic 认证是最简单的 HTTP 认证鉴权方式,认证过程简单明了,在认证过程中会直接发送明文密码,很容易导致密码泄漏,适用于安全性要求不高的系统。
2、DIGEST 认证
Digest 认证是为了为弥补 BASIC 认证存在的弱点,其用了一种nonce随机数字符串,双方约好对哪些信息进行哈希运算即可完成双方身份的验证。但是,假如认证报文被攻击者拦截,攻击者任然可以获取到受限资源,安全性还是不足。
3、BEARER 认证
BEARER 认证也可以称之为 Bearer Token 认证,我们经常使用的 JWT 就是一种 Bearer Token 认证方式。Token 是 Bearer 认证的核心,服务端通过校验 Token 合法性来进行认证授权。
第三方身份服务提供商向外暴露的 HTTP API 认证接口一般就是以上三种认证方式的其中之一。
# 模块编码
在解决了 HTTP 认证鉴权协议这个难点之后,项目代码编写也就不那么复杂了。
该模块的示意图如下:
功能特性:
- 多 HTTP 认证协议支持:BASIC、DIGEST、BARER
- 支持开发自定义添加请求头
- 支持开发者自定义添加请求参数
- 支持开发者自定义认证信息解析策略
代码设计:
subject
包:对于 Http 认证鉴权中的请求头或响应头util
包:该模块需要使用到的工具类HttpApiConfig
:这个类是一个配置类,需要由开发者配置HttpApiStrategy
:该模块的核心类,向第三方身份服务提供商发起代理请求
开发者在使用 HttpApi 模块的时候需要提供 HttpApiConfig
配置,HttpApi 模块会根据配置信息结合用户认证请求向第三方系统发起认证请求。
在这里截取几段 HttpApiStrategy
中的代码,希望能帮你更好的理解 jap-http-api
模块的代码设计:
# DEMO 演示
因为目前还没有将代码合并到 JustAuth Plus 官方仓库,所以还不能直接引用新的 HttpApi 模块。 最终版本或许与当前版本有差异,在这里只做演示。
运行环境说明:
系统:MacOS BigSur 11.4
编译器:IntelliJ IDEA 2021.1.3
JDK:11.0.11
Maven:3.6.3
2
3
4
以下的代码演示了开发者如何在自己的业务系统中集成 jap-http-api
模块。
1、导入 JAP Maven 依赖
<!-- https://mvnrepository.com/artifact/com.fujieid/jap -->
<dependency>
<groupId>com.fujieid</groupId>
<artifactId>jap</artifactId>
<version>1.0.3</version>
<type>pom</type>
</dependency>
2
3
4
5
6
7
2、编写测试 Controller 使用 jap-http-api
模块 API
@GetMapping("/basic")
public ResponseEntity authBasic(HttpServletRequest request, HttpServletResponse response ){
HttpApiStrategy httpApiStrategy = new HttpApiStrategy(new JapHttpApiUserService(), new JapConfig());
// 配置 HttpApi 模块
HttpApiConfig httpApiConfig = new HttpApiConfig()
// 指定第三方 Http认证类别
.setAuthSchema(HttpApiConfig.AuthSchemaEnum.BASIC)
// 指定第三方 Http认证方式
.setHttpMethod(HttpApiConfig.HttpMethodEnum.GET)
// 指定用户传入认证信息存放的位置
.setAuthInfoField(HttpApiConfig.AuthInfoFieldEnum.BODY)
// 指定第三方的登陆地址(我启动了一个本地服务当作第三方系统)
.setLoginUrl("localhost:8088/api/v1/source1");
// 将认证信息交给 http-api 模块,http-api 模块负责代理验证
JapResponse authenticate = httpApiStrategy.authenticate(httpApiConfig, request, response);
// 获得认证结果
if(authenticate.isSuccess()){
return new ResponseEntity(200,"login success",authenticate.getData());
}else{
return new ResponseEntity(403,"login failure",authenticate.getData());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
3、模拟用户发送登陆请求,进行测试
# 项目总结
首先,最最最重要的就是明确需求。最开始接到项目的时候,我对项目需求的理解其实是产生了一些偏差的。我起初以为是实现一个 RESTFul 风格的完整的认证鉴权框架,但是项目的实际需求和我理解的完全不同。在没有透彻的理解需求的情况下就开始了编码工作,做了很多无用功,也浪费了时间精力,我想这也是很多小伙伴在初次接触项目开发时常犯的错误吧,哈哈。
其次,这个项目主要就是 Http 认证鉴权协议的落地实现,所以需要查阅很多权威资料,包括但不限于各种文献、RFC文档、百科,在此期间接触到很多了新的名词、概念。而且需要在理解需求之后将其转化为编码实现。
关于编码方面,设计一个框架,需要考虑到框架的易用性、代码的健壮性、代码的规范性等,能够做好这些,对编码能力有很大的提升。在进行编码的过程中还需要做好规划,那一部分代码编写优先级最高,比如我在编码开始之前就进行了规划安排。
# 参考文献
- RFC7617-The 'Basic' HTTP Authentication Scheme (opens new window)
- RFC7235-Hypertext Transfer Protocol (HTTP/1.1): Authentication (opens new window)
- RFC7519-JSON Web Token (JWT) (opens new window)
- RFC2069-An Extension to HTTP : Digest Access Authentication (opens new window)
- HTTP 身份验证 - HTTP | MDN (mozilla.org) (opens new window)
- Other authentication methods - GitHub Docs (opens new window)
- HTTP摘要认证 - 维基百科,自由的百科全书 (wikipedia.org) (opens new window)