中国人社微服务实践

1. 技术考虑

1.1

1.2 网关

网关主要考虑zuul和Spring Cloud Gateway

  • Q: 为什么选Spring Cloud Gateway?

    A: 支持限流和非阻塞API,基于Filter 链很容易扩展

  • Q: 你主要用网关做了什么

    A:

    1. 通过动态路由转发到对应的服务
    2. 负载均衡(以lb:// 开头)
    3. 全局过滤器:
      1. 认证授权:设置统一的请求头,其他微服务通过请求头来判断是否走了网关()
      2. 请求之前,打印请求日志(自定义GlobalFilter)
      3. 过滤掉那些禁止外部调用的地址(自定义GlobalFilter)
    4. 对验证码进行限流(使用阿里Sentinel 做的网关限流)
    5. 对网关请求异常做统一处理
    6. 对服务断路器做降级处理(Hystrix)
    7. 跨域设置

1.3 授权认证服务

  • Q: 你授权认证服务具体都做写什么

    1. 实现OAuth2 认证(通过spring security 和 spring oauth)

    2. 配置一个认证服务器(AuthorizationServer) 和 资源服务器(ResourceServer)

      1. 认证服务器(AuthorizationServer)
        1. 客户端详情(ClientDetailsServiceConfigurer)通过JdbcClientDetailsService来读取数据库中的client 信息,并将它们保存在redis中
        2. 令牌端点(Token Endpoint)的安全约束(AuthorizationServerSecurityConfigurer),本应用暂没配置,用Spring Security来配置
        3. 配置端点接入 AuthorizationServerEndpointsConfigurer
          1. TokenStore保存token之类的管理操作,包含配置了RedisTokenStore和JwtTokenStore
          2. 配置userDetailsService管理用户信息,从数据库中查出用户信息,校验用户权限
          3. 配置 认证管理器(authenticationManager),Grant Type设置为password,因为设置了密码
          4. 自定义异常处理exceptionTranslator
    3. 验证码生成与校验
    4. 验证码过滤器
      1. 将所有HTTP请求拦截,获取请求头,从请求头中获取clientId
      2. 判断请求是否为 /oauth/token,或者一些要认证的接口
      3. 转发到验证码验证
      4. 验证通过再请求对应的请求
    5. 注册、登录查找用户信息等
    6. 第三方登录
    7. 授权客户端管理(客户端包括,app,swagger,前端)

    Q: 如何确定当前登录用户

    通过SecurityContextHolder存储安全上下文,就能知道当前的用户是谁,是否已经被认证,用户拥有哪些权限。

    原理:通过ThreadLocal 来存储认证信息

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    Object principalObj = authentication.getPrincipal();
    

    注:principalObj 为ChinahrssAuthUser, 它实现了org.springframework.security.core.userdetails.user 接口

    Q:在什么时候添加请求token

    在刷新token和登录的时候,才添加请求头 认证token。

    这个认证的token 是包含了client_id和client_secret,通过Base64加密

    // 获取令牌时,请求头信息(Basic Base64.encode(client_id:client_secret))
     authorizationValue: 'Basic ZmViczoxMjM0NTY=',
    

1.4 系统服务

Q: 系统服务服务的主要做什么?

  1. 登录,记录登录日志,更新登录时间

  2. 获取用户显示菜单和对应的路由

  3. 获取用户首页相关显示信息
  4. 部门:增删改查导出
  5. 用户:增删改查导出
  6. 角色:增删改查导出
  7. 菜单:增删改查导出
  8. 操作日志:对关键操作增加操作日志,添加自定义注解(@ControllerEndpoint )进行操作日志的添加
  9. 应用登录日志:增删查导出
  10. 线程池实例 ThreadPoolTaskExecutor

Q: 如何做分页

  1. 依赖mybatisplus

  2. 继承ServiceImpl

  3. 通过page方法查询分页数据

    QueryWrapper<Log> queryWrapper = new QueryWrapper<>();
               queryWrapper.lambda().eq(Log::getUsername, log.getUsername().toLowerCase());
                 Page<Log> page = new Page<>(request.getPageNum(), request.getPageSize());
    
    this.page(page, queryWrapper);
    

1.5 监控服务

使用Spring Boot Actuator 和 Spring Boot Admin监控微服务的状态

1.5 基础服务

  1. 通过拦截器将未经过网关的请求拦截( implements HandlerInterceptor)
  2. 供各个微服务 security 的资源服务的
    1. 没有权限访问该资源情况 (implements AccessDeniedHandler)
    2. Token 无效的情况( implements AuthenticationEntryPoint )
  3. 全局的异常处理(@RestControllerAdvice)

1.5.1 链路追踪

  1. RabbitMQ用于收集Sleuth提供的追踪信息,
  2. 然后zipkin Server 从RabbitMQ里获取

1.5.2 日志

  • sql日志打印

    P6spy输出最终数据库sql日志

  • 日志收集

    使用ELK 做对各微服务做日志收集

1.6 相关注解作用

  • ControllerEndpoint:

    • 经过具体controller 的端点,然后通过 aspectj aop将controller的信息保存到日志中。

    • 保存的日志的信息包含:方法、ip、操作、用户名、开始时间、结束时间

    • 未保存成功的抛出异常,不记录日志
    @ControllerEndpoint(operation = "新增部门", exceptionMessage = "新增部门失败")
     public void addDept(@Valid Dept dept) {
            this.deptService.createDept(dept);
    }
    

results matching ""

    No results matching ""