SpringCloud——Gateway(Predicate断言工厂、Filter过滤器工厂、token校验)

Predicate断言工厂使用(了解)

在gateway启动时会加载一些路由断言工厂(判断一句话是否正确 一个boolean表达式)
在这里插入图片描述
具体可以在官网查看添加链接描述
注:不能作用在动态路由上

Filter过滤器工厂(重点)

介绍

gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入 Http 请求和返回 Http 响应
在这里插入图片描述

使用

创建一个类,继承GlobalFilter,Ordered

继承GlobalFilter可以重写他的filter方法,从exchange可以得到request、response,从而获得想要的数据,而Ordered是将过滤器排序的类,重写getOrder() 方法,返回参数越小,过滤器越先执行

/**
 * 定义了一个过滤器
 */
@Component
public class MyGlobalFilter implements GlobalFilter , Ordered {
    /**
     * 这个就是过滤的方法
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //针对请求的过滤 拿到请求 header
        //ServerHttpRequest webflux里面 响应式里面的
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        System.out.println(path);
        String methodName = request.getMethod().name();
        System.out.println(methodName);
        String hostName = request.getRemoteAddress().getHostName();
        System.out.println(hostName);

        //响应相关的数据
        ServerHttpResponse response = exchange.getResponse();

        //放行,到下一个过滤器
        return chain.filter(exchange);
    }

    /**
     * 指定顺序的方法
     * 越小越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

测试:
在这里插入图片描述
在这里插入图片描述
若不放行,代码:

//响应相关的数据
ServerHttpResponse response = exchange.getResponse();
//一般通过json传递数据
//{"code":"200","msh","ok"}
//设置编码 响应头里设置
response.getHeaders().set("content-type","application/json;charset=utf-8");
//组装业务返回值
HashMap<String, Object> map = new HashMap<>(4);
map.put("code", HttpStatus.UNAUTHORIZED.value());
map.put("msg","未授权");
ObjectMapper objectMapper = new ObjectMapper();
//把map转换成一个字节
byte[] bytes = new byte[0];
try {
    bytes = objectMapper.writeValueAsBytes(map);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}
//通过buffer工厂将字节数组包装成一个数据包
DataBuffer wrap = response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(wrap));

测试:
在这里插入图片描述

IP黑名单拦截

校验ip一般有较大的并发量,一般不用mysql,这里采取将黑名单写入内存中

/**
 * ip黑名单校验
 */
public class IPFilter implements GlobalFilter, Ordered {
    public static final List<String> BLACK_LIST = Arrays.asList("192.1.1.1","193.1.1.1");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String ip = request.getHeaders().getHost().getHostString();
        if(! BLACK_LIST.contains(ip)){
            return chain.filter(exchange);
        }
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().set("content-type","application/json;charset=utf-8");
        HashMap<String, Object> map = new HashMap<>(4);
        map.put("code", 488);
        map.put("msg","你是黑名单");
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = new byte[0];
        try {
            bytes = objectMapper.writeValueAsBytes(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(wrap));
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

测试:
在这里插入图片描述

token校验

设计

token校验的本质就是让服务知晓访问的客户端
在这里插入图片描述

1.完善login-service

接着之前创建的login-service写代码
添加lombok依赖

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

创建entity

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class User {
    private Integer id;
    private String name;
    private String pwd;
    private Integer age;
}

引入redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.3.9.RELEASE</version>
</dependency>

接下来写controller,假设已经从数据库中查出数据

@RestController
public class LoginController {
    @Autowired
    public StringRedisTemplate redisTemplate;

    @GetMapping("doLogin")
    public String doLogin(String name,String pwd){
        System.out.println(name);
        System.out.println(pwd);
        //假设这里做了登录
        User user = new User(1,name,pwd,20);
        //token
        String token = UUID.randomUUID().toString();
        //存起来
        redisTemplate.opsForValue().set(token,user.toString(), Duration.ofSeconds(7200));
        return token;
    }
}

启动服务,接着在gateway-server中引入redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.3.9.RELEASE</version>
</dependency>

写一个过滤器,为TokenCheckFilter

/**
 * token校验
 */
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {
    public static final List<String> ALLOW_URL = Arrays.asList("/02-login-service/doLogin","/myUrl","/doLogin");
    @Autowired
    public StringRedisTemplate redisTemplate;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * 前提是和前端约定好放在哪,一般放在请求头里面(key Authorization,value bearer token)
         * 1.拿到请求url
         * 2.判断放行
         * 3.拿到请求头
         * 4.拿到token
         * 5.校验
         * 6.放行/拦截
         */
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        if(ALLOW_URL.contains(path)){
            return chain.filter(exchange);
        }
        //检查
        HttpHeaders headers = request.getHeaders();
        List<String> authorization = headers.get("Authorization");
        if(!CollectionUtils.isEmpty(authorization)){
            String token = authorization.get(0);
            if (StringUtils.hasText(token)){
                //约定好有前缀的bearer token
                String realtoken = token.replace("Bearer ", "");
                if(StringUtils.hasText(realtoken)&&redisTemplate.hasKey(realtoken)){
                    return chain.filter(exchange);
                }
            }
        }
        //拦截
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().set("content-type","application/json;charset=utf-8");
        HashMap<String,Object> map = new HashMap<>(4);
        //返回401
        map.put("code", HttpStatus.UNAUTHORIZED.value());
        map.put("msg","未授权");
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = new byte[0];
        try {
            bytes = objectMapper.writeValueAsBytes(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer wrap = response.bufferFactory().wrap(bytes);

        return response.writeWith(Mono.just(wrap));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

开启网关启动类

测试

使用Postman进行测试
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值