当前位置: 首页 > article >正文

java脚手架系列9-统一权限认证gateway

之所以想写这一系列,是因为之前工作过程中有几次项目是从零开始搭建的,而且项目涉及的内容还不少。在这过程中,遇到了很多棘手的非业务问题,在不断实践过程中慢慢积累出一些基本的实践经验,认为这些与业务无关的基本的实践经验其实可以复刻到其它项目上,在行业内可能称为脚手架,因此决定将此java基础脚手架的搭建总结下来,分享给大家使用。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中主要使用基本框架是 spring-boo-2.3.12.RELEASE和spring-cloud.-Hoxton.SR12,所有代码都在commonFramework项目上:https://github.com/forever1986/commonFramework/tree/master

目录

  • 1 gateway
  • 2 动态加载路由表
  • 3 鉴权功能

1 gateway

之所以将gateway放在这里讲,是因为承接上一篇的OAuth2,其中gateway有一个重要的功能就是鉴权,可以结合OAuth2进行鉴权。
在我们使用微服务架构的时候,免不了需要一个网关,而对于java项目来说,gateway是一个很好的选择。一般实践中,gateway有以下功能:

  • 路由转发:根据请求的特定条件(如 URL路径、请求参数、请求头等)来将请求转发到后端的多个服务,并支持动态路由配置
  • 过滤功能:提供了一套过滤器机制,允许开发人员对请求进行修改和验证,以及应用各种策略,如认证、安全、监控/指标、限流、日志、请求转发/重试等
  • 容错处理:集成断路器(Hystrix),为微服务网关提供容错处理的功能
  • 服务发现:与服务注册中心集成,动态从服务注册中心获取服务信息并进行路由
  • 请求转发:进行请求的协议转换,比如将 HTTP 请求转换成 WebSocket 请求
  • 请求限流:支持通过配置限流规则,对请求进行限流,防止恶意请求或异常情况下的流量冲击

下面以动态读取路由配置+过滤功能,实现gateway的路由转发可以动态加载,以及实现鉴权功能

2 动态加载路由表

参考gateway子模块

在实际应用中,我们不可能将路由配置放入项目的yaml配置文件中,这样修改路由时,都需要重新启动或者发布。这时候,配置中心就起到动态配置路由转发的存储功能,同时gateway也提供RouteDefinitionRepository可进行路由表动态加载。

原理:将路由配置文件放入nacos中,gateway子模块通过实现RouteDefinitionRepository,监听nacos的路由配置文件,实现动态更新路由配置

1)创建gateway子模块,引入以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--监听配置文件的更新 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--获取配置文件 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2)配置bootstrap.yml,要配置服务发现和配置中心的信息

server:
  port: 9991
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
      config:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
        file-extension: yaml
        group: DEFAULT_GROUP
        prefix: ${spring.application.name}

3)实现NacosRouteDefinitionRepository(实现RouteDefinitionRepository),用于自动监听配置文件并刷新路由表

package com.demo.route.config;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * nacos路由数据源
 */
@Component
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private static final Logger logger = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);

    private static final String SCG_DATA_ID = "cloud-gateway-service";
    private static final String SCG_GROUP_ID = "DEFAULT_GROUP";

    private final ApplicationEventPublisher publisher;

    private final NacosConfigManager nacosConfigManager;

    public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigManager nacosConfigManager) {
        this.publisher = publisher;
        this.nacosConfigManager = nacosConfigManager;
        addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitionList = new ArrayList<>(0);
        try {
            String configContent = nacosConfigManager.getConfigService().getConfig(SCG_DATA_ID, SCG_GROUP_ID, 5000);

            if (StringUtils.isNotEmpty(configContent)) {
                routeDefinitionList = JSON.parseArray(configContent, RouteDefinition.class);
            }
        } catch (NacosException e) {
            logger.error("从Nacos加载配置的动态路由信息异常", e);
        }
        return Flux.fromIterable(routeDefinitionList);
    }

    /**
     * 添加Nacos监听
     */
    private void addListener() {
        try {
            nacosConfigManager.getConfigService()
                    .addListener(SCG_DATA_ID, SCG_GROUP_ID, new Listener() {

                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        @Override
                        public void receiveConfigInfo(String configInfo) {
                            publisher.publishEvent(new RefreshRoutesEvent(this));
                        }
                    });
        } catch (NacosException e) {
            logger.error("添加Nacos监听异常", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }
}

4)设置GatewayApplication设置@EnableDiscoveryClient注册到nacos
5)在nacos的public命名空间和DEFAULT_GROUP分组中,配置nacos的路由配置名为:cloud-gateway-service的json文件

[
  {
    "id": "baidu",
    "order": 0,
    "predicates": [{
      "args": {
        "pattern": "/baidu/**"
      },
      "name": "Path"
    }],
    "uri": "http://www.baidu.com",
    "filters": [{
      "args": {
        "_genkey_0": "2"
      },
      "name": "StripPrefix"
    }]
  },
  {
    "id": "manager",
    "predicates": [{
      "args": {
        "pattern": "/manager/**"
      },
      "name": "Path"
    }],
    "uri": "http://localhost:9981",
    "filters": [{
      "args": {
        "_genkey_0": "1"
      },
      "name": "StripPrefix"
    }]
  }
]

6)通过请求以下访问,可以得到转发;同时你可以在nacos上面修改cloud-gateway-service的json文件路由,可以测试动态刷新
http://localhost:8891/baidu/aa
http://localhost:8891/business/business

3 鉴权功能

参考gateway子模块

网关的过滤功能:提供了一套过滤器机制,允许开发人员对请求进行修改和验证,以及应用各种策略,如认证、安全、监控/指标、限流、日志、请求转发/重试等。我们这里的鉴权就是使用过滤功能。在配置鉴权功能之前,我们有必要了解一下内容:

  • 鉴权原理:在系列8中我们讲过security、JWT、oauth的内容,这里利用auth-authentication子模块生成token,我们知道验证token的有效性2种方法,一种是使用访问auth-authentication子模块的access_token接口验证,一种是通过RSA非对称加密验证。这里的token采用RSA非对称加密验证(这是因为本身路由访问非常频繁的服务,不适合频繁访问access_token接口)。
  • gateway过滤:在gateway中有3个比较重要的过滤:ReactiveAuthenticationManager->ReactiveAuthorizationManager->Gateway Filters。

1)其中ReactiveAuthenticationManager用于封装JWT为OAuth2Authentication并判断Token的有效性;
2)ReactiveAuthorizationManager用于基于URL的鉴权;
3)Gateway Filters是网关的过滤流程。

下面我们通过配置JWT+RSA的解密对token进行认证,另外通过实现ReactiveAuthorizationManager对其进行鉴权。
1)引入以下依赖:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

3)编写ResourceServerManager(实现ReactiveAuthorizationManager),实现其check接口,获得用户信息,对权限进行判断(这里只是演示一下,没有实际权限判断代码,实际业务中可以加入一些权限判断,比如路由权限、RABC等业务判断功能)
4)编写ResourceServerConfig,通过注入securityWebFilterChain类,将JWT认证和ResourceServerManager都设置到过滤链中
5)在ResourceServerConfig中,通过注入jwtAuthenticationConverter,实现JWT+RSA的公钥,对token进行认证
6)编写SecurityGlobalFilter(实现GlobalFilter,和Ordered),做最后处理(当然如果没有此需求,也可以不做处理)
7)通过请求以下访问,可以得到转发(前提是你需要在header中增加token)
http://localhost:8891/baidu/aa
http://localhost:8891/business/business


http://www.kler.cn/news/367362.html

相关文章:

  • IP数据报的 分片与组装技术 深度解析
  • 基于SSM考研助手系统的设计
  • 配置nginx服务通过ip访问多网站
  • C#之Aes加密解密
  • es实现桶聚合
  • sharpkeys-键盘部分按键不好用,用其它不常用按键代替
  • 基于MWORKS的蓝桥杯「智能装备数字化建模大赛」正式发布,首期培训本周六开启
  • C++结合图形编程与物联网:你更偏向哪种方式来学习信息学奥赛?
  • 如何应对 Android 面试官 -> ANR 如何优化?线上 ANR 如何监控?
  • 计算机网络:网络层 —— IPv4 地址与 MAC 地址 | ARP 协议
  • <Project-11 Calculator> 计算器 0.5 液体、长度、温度单位 转换器 liquid_measures HTML JS
  • 【NIPS24】【Open-Ended Object Detection】VL-SAM
  • 【从零开始】2. Dell PowerEdge 人工智能服务搭建(番外篇)
  • 【MySQL】索引和事务
  • mongodb 导入导出索引--查询慢问题
  • 4404 - 提高:二分与三分:曲线(三分)
  • 企业数据高效集成案例:钉钉到MySQL的数据同步
  • C语言二刷指针篇
  • 安装 Pycharm-Community
  • 【数据结构】贪心算法:决策的艺术
  • 厨艺交流平台:Spring Boot技术实践案例
  • springboot061基于B2B平台的医疗病历交互系统(论文+源码)_kaic
  • 基于SSM+微信小程序的社区垃圾回收管理系统(垃圾1)
  • 轻松构建高效 API:FastAPI 的主要特点与实战应用20241027
  • JDK、JRE、JVM之间的关系
  • sudo chroot raw-rootfs