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
}));
}
};
}
}
由于时间关系,只能将代码放上来先,还有些理论及一些坑还没整理,希望可以帮助更多热爱学习分享的朋友。也有些因为敏感字眼进行了修改,所以有问题请随时留言,有时间会来修改整理的,谢谢各位 @_@
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfjbgif
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13