5.HTTP请求参数解析
解析 HTTP 网络请求的参数信息,包括;GET/POST,以及应对不同 Content-Type 类型的处理。
HTTP 接口请求的参数需要解析成可以匹配到 RPC 接口的入参信息,所以通常为了方便控制一般只支持 RPC 接口单个对象入参,并且不允许同名不同参数的重载方法出现,这些会在 RPC 方法注册阶段进行报错提醒。
HTTP 接口请求的参数需要解析成可以匹配到 RPC 接口的入参信息,所以通常为了方便控制一般只支持 RPC 接口单个对象入参,并且不允许同名不同参数的重载方法出现,这些会在 RPC 方法注册阶段进行报错提醒。
流程图:
从网络通信(解析HTTP协议)到会话处理,需要对 GET/POST 的请求,以及请求的参数类型 Content-Type 做细化的参数解析操作。
具体实现步骤:
1.定义一个专门解析HTTP请求的请求解析器RequestParser,定义成员变量FullHttpRequest,使用流来解析获取Content-type,然后获取请求类型,然后根据不同的请求类型将请求参数存储到一个Map中。
2.在自定义的会话服务处理器GatewayServerHandler中使用上面的请求解析器RequestParser对http请求进行解析。
3.在默认会话实现类DefaultGatewaySession中进行消息封装,然后从连接池中获取到连接对象,执行execute方法,将消息传递进去。
6.引入执行器封装服务调用
通过引入执行器解耦会话中流程对数据源(RPC)的处理,让整个流程更加干净、整洁易于扩展和维护。
之前对于 HTTP 请求到网络协议转换后,就是会话流程的处理。但在会话流程中还有些内容过于冗余,这些内容就是对数据源(RPC)的调用时入参和出参的封装,它们应该被提取到一个专门的类来处理,这样才能更加方便的管理。会话的职责是负责串联上下文,执行器的职责是负责对数据源的调用信息处理
具体实现步骤:
1.创建executor包,作为封装对数据源(RPC)的调用,以及处理相关的入参、出参信息。同时这里还会把网关的调用结果进行封装到一个标准的类中,类里包括了code码、info描述,以及 data 结果信息。
2.在executor包下再创建一个result包,里面创建GatewayResult类,用于封装调用结果的消息。
3.创建一个Executor接口,用于定义执行数据源调用的逻辑。创建一个执行器抽象基类BaseExecutor实现Executor接口,定义doExec抽象方法,实现接口方法exec里面调用doExec用于执行数据源调用,里面封装了用于获取调用参数的Configuration会话配置类以及用于建立连接的Connection接口。创建简单执行器SimpleExecutor基础BaseExecutor,重写doExec方法用于执行数据源调用。
7.权限认证组件(Shiro+Jwt)
引入Shiro、Jwt 整合两部分功能,提供出认证服务。为后面在网络通信中验证 Token 信息做准备。
在我们的实现的InfiniGate自研网关中,当接收 HTTP 请求以后,开始调用对应的 RPC 接口前,其实还应该做一步权限验证。也就是说你当前调用的 HTTP 接口是否含带了我授予的 Token 信息,这个 Token 是否在有效期范围等控制,这样才能保证一个 HTTP 的调用和返回结果是安全可靠的。
- 关于网关中权限的校验会使用到 Shiro + Jwt,同时还要提供单独的 Handler 来处理 Netty 中的通信对信息的校验处理。但鉴于这部分属于两块功能,所以这里只先完成关于 Shiro + Jwt 部分。
- 为什么不用Spring Security而用的是Apache Shiro呢?因为它相当简单。对比于 Spring Security,可能没有做的功能强大,但是在实际工作时并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。还有一个原因就是这个核心通信组件没有引入Spring的环境,如果要使用Spring Security就要引入Spring的环境,影响这个核心通信组件的可扩展性。
具体实现:
1.创建JWTUtil类,用于生成JWT Token 字符串和解析JWT Token字符串。
2.创建IAuth接口,作为认证服务接口。创建AuthService类实现IAuth,重写validate方法。AuthService里面封装了Subject类,Subject就是主体,代表了当前 “用户”。通过subject进行身份验证。
3.因为我们这里不只是用户名密码验证,也会在后续扩展一些其他的网络请求信息或者授权操作,所以我们需要单独提供一个 AuthenticationToken 和 AuthorizingRealm 验证领域的实现类。
8.网关会话鉴权处理
通过拆分 Handler 通信管道处理器,引入 Shiro + JWT 到 AuthorizationHandler 中处理鉴权操作。
上面提到引入了 Shiro + JWT 作为鉴权的工具,这个工具就是要用到此处用于处理网络会话请求中对接口访问信息的一个鉴权处理。
这里你可以思考🤔,一次网络请求经过 Netty 处理可以分为三段;消息接收、请求鉴权、消息处理。这样就由原来我们只是在接收消息后直接把消息协议转换后请求到 RPC 服务,转换为多添加二层来处理简单的消息接收和请求鉴权。这里的请求鉴权就是基于引入的 Shrio + JWT 完成
具体实现:
1.在HttpStatement 中新添加字段 auth 用于判断是否需要鉴权。
2.在GatewayServerHandler中的调用会话服务改为从http请求中获取到HttpStatement,将HttpStatement保存到管道的属性信息中,channel.attr(AgreementConstants.HTTP_STATEMENT).set(httpStatement),所有的这条通信链上都可以获取到,这样到鉴权处理中直接获取到信息就可以操作了。此处不去获取会话的信息了(gatewaySessionFactory.openSession(uri))避免如果鉴权都鉴权失败了,创建会话服务也是浪费资源。所以只需要在构造函数中传输 Configuration 即可,用于根据 URI 获取 HttpStatement 网关接口映射信息,方便拿到是否需要鉴权。
3.创建AuthorizationHandler用于鉴权,鉴权的操作首先要获取当前请求的 URI 是否配置了鉴权,如果不鉴权则直接放行。进入到鉴权,通过FullHttpRequest获取到鉴权信息,先做非空判断,然后调用上面定义的鉴权接口auth.validate(),此处做了一点封装,将鉴权接口放到了configuration中封装成authValidate()方法。
4.创建ProtocolDataHandler,这里就相当于把原来的GatewayServerHandler中的解析请求参数,获取会话并调用会话服务,然后封装返回结果放到了ProtocolDataHandler中。