IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringCloud+nacos+UserDetails(权限)+过滤器(gateway自定义+全局) -> 正文阅读

[Java知识库]SpringCloud+nacos+UserDetails(权限)+过滤器(gateway自定义+全局)

故事背景

摸鱼监督者要做个新微服务架构要实现
1、简单的鉴权及IP限定
2、全局及自定义过滤器扩展

网上看了些文章作为参考,如果侵权请告知及时删除
SpringCloud-路由网关Gateway自定义GatewayFilterFactory
只是本着学习及分享并无恶意^ _ ^

项目架构及版本

JDK 17
SpringCloud 2021.0.0
SpringBoot 2.6.3
NACOS Server 2.0.3 (主要实现配置+发现服务)

简单服务

只是一个可以正常访问的controller
如果有特别的配置就扔到NACOS上

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ap.demo</groupId>
    <artifactId>qwer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>qwer</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.0</spring-cloud.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2021.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.1</version>
        </dependency>        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>   
        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>             
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>

            </plugin>
        </plugins>
    </build>

</project>

App.java

@SpringBootApplication
// 开启发现服务
@EnableDiscoveryClient
public class QwerApplication {

    public static void main(String[] args) {
        SpringApplication.run(QwerApplication.class, args);
    }
}

Controller

@RestController
@RequestMapping("/hub")
@Slf4j
public class APController {

    @GetMapping("/say")
    public String sayHello(HttpServletResponse rsp) {
        log.info("say service was call.");
        rsp.addHeader("ap", "andy");
        return "Hello";
    }
    @GetMapping("/hi")
    public Object test(HttpServletResponse rsp) {
        
        rsp.addHeader("ap", "yanLao");
        return "hi";
    }
    
}

Bootstrap.yml

spring:
  application:
    name: qwer
  cloud:
    inetutils:
      preferred-networks:
      - 192.
    nacos:
      config:
        # 配置文件优先级 application-*.yaml > extension-configs > shared-configs
        # 服务器地址
        server-addr: 192.168.20.111:8848
        # 命名空间
        namespace: develop
        # 组别以项目名区分
        group: develop
        # 后缀,暂时支持properties 或 yaml
        file-extension: yaml
        name: qwer
      discovery:
        server-addr: 192.168.20.111:8848
        namespace: develop
        group: develop
server:
  port: 8090

GateWay 网关

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ap.demo</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.0</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2021.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>        
    </dependencies>

    <build>
		<finalName>gateway</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<executable>true</executable>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

			<!-- 排除所有配置文件,读取目录下的配置文件 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
			</plugin>

			<!-- 打包时跳过测试 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

bootstrap.yml

spring:
  application:
    name: gateway
  cloud:
    inetutils:
      preferred-networks:
      - 192.
    nacos:
      config:
        server-addr: 192.168.20.111:8848
         # 命名空间
        namespace: develop
        # 组别以项目名区分
        group: develop
        name: gateway
        file-extension: yml
        # 额外用户配置
        extension-configs:
        - data-id: ap-gateway-user.yml
          group: DEFAULT_GROUP
          refresh: true
      discovery:
        server-addr: 192.168.20.111:8848
        namespace: develop
        group: develop
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      # 路由 只要访问hub开头的都访问qwer服务
      routes:
      - id: qwer
        uri: lb://qwer
        predicates:
        - Path=/hub/**
        filters:
        # 后缀GatewayFilterFactory可以直接省略
        - APCustom
        # 传参方法
        # - APCustom=abc

ap-gateway-user.yml 用户密码

ap:
  gateway:
    api:
      users:
        - test:test123456

gatewayapplication

@SpringBootApplication
@EnableDiscoveryClient
@EnableEncryptableProperties
@ConfigurationPropertiesScan("com.ap.gateway.config")
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

apiUserDetail

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@Data
@Service
@Slf4j
@ConfigurationProperties(prefix="ap.gateway.api")
public class ApiUserDetailsService implements ReactiveUserDetailsService {
	/** 用户名和密码的分隔符 */
    private static final String SPLITER = ":";
    private List<String> users;
    private Map<String, UserDetails> userMap;
    @PostConstruct
    public void init() {
        this.userMap = new HashMap<>();
        users.forEach(user -> {
            String[] userPasswd = user.split(SPLITER);
            if (userPasswd.length != 2) {
                return;
            }
            PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
            UserDetails userDetails = User.builder()
                    .passwordEncoder(encoder::encode)
                    .username(userPasswd[0])
                    .password(userPasswd[1])
                    .roles("USER")
                    .build();
            this.userMap.put(userDetails.getUsername(), userDetails);
        });
    }
    @Override
    public Mono<UserDetails> findByUsername(String username) {
        UserDetails result = this.userMap.get(username);
        if (result != null) {
            log.debug("User found for {}", username);
            return Mono.just(User.withUserDetails(result).build());
        } else {
            log.warn("User not found for {}", username);
            return Mono.empty();
        }
    }
}

GatewaySecurityConfiguration

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfiguration {
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
         http.csrf()
                 .disable()
              .authorizeExchange()
                   .anyExchange().authenticated()
                        .and()
                   .httpBasic();
         return http.build();
    }
}

全局过滤器

无需配置 直接生效

@Component
@Slf4j
public class CustomGlobalGatewayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 请求可以先处理,响应只能在下边内容中处理 exchange可以获取上下文内容
        // chain.filter(exchange)的返回值是获取不到任何的响应信息的,最好学习一下reactor
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 获取请求头
            HttpHeaders req = exchange.getRequest().getHeaders();
            log.info("ap: ", req.get("ap");
            // 获取响应头
            HttpHeaders resp = exchange.getResponse().getHeaders();
            log.info("ap: ", resp.get("ap");
        }));
    }
    /**
     * 过滤器权重, 数字越低优先级越高
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

自定义过滤器

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;


@Component
@Slf4j
public class APCustomGatewayFilterFactory extends AbstractGatewayFilterFactory<APCustomGatewayFilterFactory .Config>  {
/* 类名:APCustomGatewayFilterFactory  后缀要用GatewayFilterFactory否则无法生效 *、
    public APCustomGatewayFilterFactory () {
        super(JFLogGatewayFilterFactory.Config.class);
    }
    /* 配置 特殊参数 */
    public static class Config{
        /* 特殊字段预留待用 */ 
        private String data;
        /** @return 返回data */
        public String getData() {
            return data;
        }
        /** @param data 设置data */
        public void setData(String data) {
            this.data = data;
        }
    }
    
    /* 快速配置 可以直接在gateway配置里赋值 */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("data");
    }
  
    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                // 待开发
                String data = config.getData(); // abc
                }));
            }
        };
    }
}

由于时间关系,只能将代码放上来先,还有些理论及一些坑还没整理,希望可以帮助更多热爱学习分享的朋友。也有些因为敏感字眼进行了修改,所以有问题请随时留言,有时间会来修改整理的,谢谢各位 @_@

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:07:36  更:2022-03-16 22:10:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:55:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码