Gateway过滤器和token校验实战

Filter过滤器工厂

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

按生命周期分两种

pre在业务逻辑之前 post在业务逻辑之后

GatewayFilter需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 DefaultFilters。
GlobalFilter全局过滤器,不需要配置路由,系统初始化作用到所有路由上
全局过滤器统计 :请求次数,限流 ,token的校验, ip黑名单拦截,跨域本质(filter) 144开头的电话限制一些 ip的访问

官方文档查看过滤器

https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gatewayfilter-factories

自定义网关过滤器(重点)

全局过滤器的优点的初始化时默认挂到所有路由上,我们可以使用它来完成 IP过滤,限流等功能

创建配置类 GlobalFilterConfig

@Component
@Slf4jpublic 
class GlobalFilterConfig implements GlobalFilter, Ordered{
@Override //重写filter方法
public  Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	log.info("进入了我自己的全局过滤器");
	String token = exchange.getRequest().getQueryParams().getFirst("token");
	if (token == null) {
	log.error("token为空,说明没有认证");
	exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
	return exchange.getResponse().setComplete();
	}
	log.info("验证通过");
	return chain.filter(exchange);
	}
/*** order越小越先执行**
 @return*/
@Overridepublic
 int getOrder() {
 return 0;
 }


}

访问测试

http://localhost/info?token=asdad

IP认证拦截实战

创建 IPGlobalFilter

@Component@Slf4jpublic
 class IPCheckFilter implements GlobalFilter, Ordered {
 @SneakyThrows
 @Override
 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
 String ip = exchange.getRequest().getHeaders().getHost().getHostName();
 //这里写死了,只做演示
    if (ip.equals("localhost")) {
    //说明是黑名单里面的
     ipServerHttpResponse response = exchange.getResponse();
     response.setStatusCode(HttpStatus.UNAUTHORIZED);
     Map<String, Object> map = new HashMap<>();
     map.put("code", HttpStatus.UNAUTHORIZED);
	 map.put("msg", "非法访问");
	response.getHeaders().add("content-Type","application/json;charset=UTF-8");
	ObjectMapper objectMapper = new ObjectMapper();
 	byte[] bytes = objectMapper.writeValueAsBytes(map);
	 DataBuffer buffer = response.bufferFactory().wrap(bytes);return response.writeWith(Mono.just(buffer));
	}
	return chain.filter(exchange);
	}
/***设置此过滤器的执行顺序** @return*/
@Override
public int getOrder() {return 1;}
}

测试访问
在这里插入图片描述

token校验实战

在这里插入图片描述
登录:

@RestController
@CrossOrigin // 加上这个注解之后 这个controller里面的方法就可以直接被访问了
public class LoginController {

    @Autowired
    public StringRedisTemplate redisTemplate;

    @GetMapping("doLogin")
    @CrossOrigin
    public String doLogin(String name, String pwd) {
        System.out.println(name);
        System.out.println(pwd);
        // 这里假设去做了登录
        User user = new User(1, name, pwd, 18);
        // token
        String token = UUID.randomUUID().toString();
        // 存起来 key是token  value是登录后的user对象
        redisTemplate.opsForValue().set(token, user.toString(), Duration.ofSeconds(7200)); //过期时间7200秒
        return token;
    }

}

拦截(过滤器):

/**
 * token校验
 */
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {

    /**
     * 指定好允许放行的路径
     */                            //登录的操作 --- 放行,如果是其他的操作(如teacher-service) 就要检查是否登录过(有7200秒过期时间)
    public static final List<String> ALLOW_URL = Arrays.asList("/login-service/doLogin", "/myUrl","/doLogin");

	//注入redis对象
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 前提是? 和前端约定好 一般放在请求头里面 一般key :  Authorization (请求头里的字段)  value: bearer token
     * 1.拿到请求url
     * 2.判断放行
     * 3.拿到请求头
     * 4.拿到token
     * 5.校验
     * 6.放行/拦截
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        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");//拿到key(登录时存入的UUID)
        if (!CollectionUtils.isEmpty(authorization)) {
            String token = authorization.get(0);
            if (StringUtils.hasText(token)) { //hasText()返回值是 布尔类型的,字符串 不是 null ,并且不为空,
                        //而且不能是空白字符,只有这三个条件同时满足时才 返回 true ,其他情况均返回 false 。
                // 约定好的有前缀的 bearer token
                String realToken = token.replaceFirst("bearer ", "");
                if (StringUtils.hasText(realToken) && redisTemplate.hasKey(realToken)) {
                		//(判断redis中是否存在登录时存入的uuid) 有就放行
                    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));
    }

    /**
     * 这个顺序 最好在0附近  -2 -1 0 1
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的基于Spring Security的登录过滤器示例,包含token校验: ```java public class TokenAuthenticationFilter extends OncePerRequestFilter { private final TokenService tokenService; public TokenAuthenticationFilter(TokenService tokenService) { this.tokenService = tokenService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = getTokenFromRequest(request); if (StringUtils.hasText(token) && tokenService.validateToken(token)) { Authentication authentication = tokenService.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String getTokenFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` 这个过滤器会从请求头中获取token,并通过TokenService进行校验。如果token有效,则将认证信息放入SecurityContextHolder中,否则继续执行过滤器链。 在配置Spring Security时,需要将该过滤器添加到过滤器链中: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final TokenService tokenService; public SecurityConfig(TokenService tokenService) { this.tokenService = tokenService; } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .addFilterBefore(new TokenAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } } ``` 在配置中,我们将TokenAuthenticationFilter添加到了UsernamePasswordAuthenticationFilter之前,并且设置了sessionCreationPolicy为STATELESS,使得每次请求都需要进行认证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值