Antifrag

返回

用户端登录#

用户端的登录是基于微信小程序登录

wx小程序搭建:前端部署文档

env.js中修改本地接口

image-20240706174048764

可以看到本地请求为502

这是由于本地网关并没有配置导致的后面会进行配置

image-20240706174430919

请求参数(2个参数,code:登录临时凭证,phoneCode:获取手机号的凭证):

image-20240706174413712

拉取后端代码 sl-express-ms-web-customer

登录接口#

登录接口的实现是在com.sl.ms.web.customer.controller.UserController#login

image-20240706174821877

可以看到代码是由UserLoginVO响应数据对象和UserLoginRequestVO请求参数对象组成

我们现看看UserLoginVO响应数据对象

UserLoginRequestVO请求参数对象组成

用户微服务#

用户端通过微信登陆流程图

流程图

在Jenkins部署sl-express-ms-user-service

image-20240708105311036

image-20240708105407141

数据库已在服务器部署

小程序登录#

image-20240708105610880

通过小程序登录测试

image-20240708105827124

获取手机号#

想要获取到手机号的要先获取到微信access_token,在获取到手机号,否则获取不到

com.sl.ms.web.customer.service.impl

image-20240709104615345

image-20240709104632774

    @Test
    void getPhone() throws IOException {
        //在测试用例中输入自己获取到的 phonecode
        String phone = wechatService.getPhone("1aaaaa1111");
        System.out.println(phone);
    }
java
实现登录#

com.sl.ms.web.customer.service.impl.MemberServiceImpl#login

image-20240709104923601

生成token实现,这里采用的是RSA加密方式(密钥信息在nacos中的sl-express-ms-web-customer.properties配置)

com.sl.ms.web.customer.service.impl.TokenServiceImp

image-20240709105243144

启动服务,在小程序进行测试

image-20240709105534105

可以看到登录成功

双token三验证#

单token存在的问题#

在日常使用中,我们会频繁的进行登录,而在登录的过程中,会先生成jwt的token,前端接收到token将其保存下来,在进行后端服务请求的时候,在请求中携带token,服务端对token进行校验和鉴权,这种模式叫做 单token模式

在单token模式中,会出现token有效时间的问题,有效时间太短容易过期,太长容易被攻击截取。

在另一方面,token是无状态的,就是说我们不能自如的控制token的状态,无法让他主动失效。

方案设计#

解决问题

  • token有效期长不安全

    • 登录成功后,生成2个token,分别是:access_token、refresh_token,前者有效期短(如:5分钟),后者的有效期长(如:24小时)

    • 正常请求后端服务时,携带access_token,如果发现access_token失效,就通过refresh_token到后台服务中换取新的access_token和refresh_token,这个可以理解为token的续签

    • 以此往复,直至refresh_token过期,需要用户重新登录

  • token的无状态性

    • 为了使token有状态,也就是后端可以控制其提前失效,需要将refresh_token设计成只能使用一次

    • 需要将refresh_token存储到redis中,并且要设置过期时间

    • 这样的话,服务端如果检测到用户token有安全隐患(如:异地登录),只需要将refresh_token失效即可

代码实现#

生成刷新token#

生成刷新refresh_token的主要逻辑有两点:

  • 生成jwt格式的token,有效期时间一般小时为单位
  • 将token存入到redis,使token有状态,并且确保只能使用一次

com.sl.ms.web.customer.service.impl.TokenServiceImpl

public static final String REDIS_REFRESH_TOKEN_PREFIX = "SL_CUSTOMER_REFRESH_TOKEN_";
java

image-20240709111838201

刷新token#

刷新token的动作是在refresh_token过期之后进行的,主要实现关键点有:

  • 校验refresh_token是否被伪造以及是否在有效期内
  • 从redis中查询,是否不存在,如果不存在说明已经失效或已经使用过,如果存在,就需要将其删除
  • 重新生成一对token,响应结果

com.sl.ms.web.customer.service.impl.TokenServiceImpl

image-20240709112251066

在Controller中调用上述方法

com.sl.ms.web.customer.controller.UserController

image-20240709112416024

Service中调用

com.sl.ms.web.customer.service.impl.MemberServiceImpl

image-20240709112532232

完善用户端登录#

用户端登录成功后,需要在补一个token,之前已经写过一个了

image-20240710082924254

测试

image-20240710083035707

网关#

网关作用#

网关能够更好的管理项目分配,每一个客户端都将通过网关传递到服务端

网关就是每个客户端的中间商,他还能对token、以及用户的权限进行有效的校验

比如说:司机不能登录到快递员端,快递员不能登录到司机端

image-20240710095125453

拉取代码#

sl-express-gateway中拉取网关代码:

拉取代码后,创建develop分支进行开发

bootstrap-local.yml

自定义过滤器配置#

image-20240710095615927

过滤器实现#

在过滤器中主要实现以下几个功能:

  • 白名单放行
  • 请求头中的token是否有效
  • 权限是否匹配(校验角色)
  • 向下游微服务传递解析token的数据以及token值

代码实现:

测试#

将网关启动,测试http://127.0.0.1:9527/manager/doc.html#/home看能不能正常看到页面

image-20240710100121839

配置前端

将测试URL改为VUE_APP_BASE_URL = 'http://192.168.150.1:9527/manager'

image-20240710100159599

将代码上传git

在Jenkins构造项目

访问http://admin.sl-express.com/

image-20240710100755861

验证码端口可以看到是9527,部署成功

image-20240710100922312

代码优化#

优化一#

将校验逻辑抽取到独立的类中,这样在每个端的GatewayFilterFactory中就可以共用了。

com.sl.gateway.filter.TokenGatewayFilter

com.sl.gateway.filter.ManagerTokenGatewayFilterFactory

优化2#

通过前面的优化一已经将过滤器抽取到一个独立的类中,这样就可以在多个过滤器工厂中通用了,但也是存在一些问题的,例如:

  • 不同的终端校验的角色id是不同的
  • 用户端是不需要校验角色的
  • 用户端校验token的逻辑与其他三端是不一样的
  • 用户端请求头中的token参数名与其他三端也不一样

基于这些问题,就能够意识到,单纯的抽取代码是不够的,需要进一步的优化。想一想,该怎么优化呢?

优化的思路就是,在TokenGatewayFilter中保留四端通用的逻辑,不同的逻辑抽取到接口中,由四端具体的实现。

自定义AuthFilter接口:

com.sl.gateway.filter.AuthFilter

登录与网关配置
https://antifrag.cn/blog/sl-2
作者 l6kmw
发布于 2024年7月10日