gateway 集成springsecurity 登录时webfilter获取post请求参数

gateway 集成springsecurity 登录时获取post请求参数

1. 配置一个过滤器,手动转换body数据,修改request,这个过滤器需要放在真正操作post参数的filter之前,这个过滤器也只拦截登录方法

@Component
public class CacheBodyWebFilter extends AbstractMatchWebFilter {
    @Override
    protected Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
        HttpMethod method = exchange.getRequest().getMethod();
        if (method == null || method.matches("GET") || method.matches("DELETE")) {
            return chain.filter(exchange);
        }
        return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
            byte[] bytes = new byte[dataBuffer.readableByteCount()];
            dataBuffer.read(bytes);
            DataBufferUtils.release(dataBuffer);
            return bytes;
        }).defaultIfEmpty(new byte[0]).flatMap(bytes -> {
            DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
            ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
                @Override
                public Flux<DataBuffer> getBody() {
                    if (bytes.length > 0) {
                        return Flux.just(dataBufferFactory.wrap(bytes));
                    }
                    return Flux.empty();
                }
            };
            return chain.filter(exchange.mutate().request(decorator).build());
        });
    }

    @Override
    protected boolean shouldFilter(ServerWebExchange serverWebExchange) {
        String requestUrl = serverWebExchange.getRequest().getURI().getPath();
        return super.match(requestUrl, "/login");
    }
}

此处是获取参数的工具方法:

public class RequestUtils {
     public static Map<String,String> getFormMap(ServerHttpRequest serverHttpRequest){
            Flux<DataBuffer> body = serverHttpRequest.getBody();
            AtomicReference<String> bodyRef = new AtomicReference<>();
            Consumer<? super DataBuffer> c = (b -> {
                CharBuffer charBuffer = StandardCharsets.UTF_8.decode(b.asByteBuffer());
                DataBufferUtils.release(b);
                bodyRef.set(charBuffer.toString());
            });
            body.subscribe(c);

            String rspStr = bodyRef.get();
            if(StringUtils.isEmpty(rspStr)){
                return null;
            }
            return getFormMap(rspStr);
    }

    private static Map<String, String> getFormMap(String body) {
        if(StringUtils.isEmpty(body)){
            return null;
        }
        Map<String,String> map = new HashMap<>();
        String[] params= body.split("&");  // name=123&age=11 ==>  ['name=123','age=11']
        for(String param : params){
            String[] par = param.split("="); // name=123 ==>  ['name','123']
            if(par!=null && par.length>1){
                map.put(par[0],par[1]);
            }
        }
        return map;
    }
}

2.需要获取请求参数的过滤器。(我这里是需要实现控制登录失败的次数)

@Component
public class LoginTimesFilter extends AbstractMatchWebFilter {

	    @Override
	    protected Mono<Void> doFilter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain){
	        //获取post请求的参数map
	        Map<String, String> formMap = RequestUtils.getFormMap(serverWebExchange.getRequest());
	      	//我这里主要是处理登录失败次数限制。。。。
	      	.....
	      	
	    }
   }

3.之前的CacheBodyWebFilter因为已经读取了body,所以后边springsecurity加载用户的ReactiveUserDetailsService.findByUsername就无法自动获取用户名称了

public class ReactiveUserDetailsServiceImpl implements ReactiveUserDetailsService {
    @Override
    public Mono<UserDetails> findByUsername(String username) {
 			//此处username 为空     		
    }
}

此时需要重写 ServerAuthenticationConverter ,手动获取请求参数

public class FormLoginAuthenticationConverter extends ServerFormLoginAuthenticationConverter {


    private ServerHttpBasicAuthenticationConverter serverHttpBasicAuthenticationConverter = new ServerHttpBasicAuthenticationConverter();

    @Override
    public Mono<Authentication> convert(ServerWebExchange exchange) {
        String uri = exchange.getRequest().getURI().getPath();
        if("/login".equals(uri)){  //登录操作才对body做特殊操作,其他请求直接调用原有请求
            UsernamePasswordAuthenticationToken authentication = createAuthentication(exchange);
            if(authentication==null){
                return Mono.empty();
            }
            return Mono.just(authentication);
        }else{ //非登录操作,基本不用在网关里读取body,默认方法就行
            return serverHttpBasicAuthenticationConverter.convert(exchange);
        }
    }

    private UsernamePasswordAuthenticationToken createAuthentication(ServerWebExchange exchange) {
    	//获取post请求的参数map
        Map<String, String> formMap = RequestUtils.getFormMap(exchange.getRequest());
        if(CollectionUtils.isEmpty(formMap)){
            return null;
        }
        String username = formMap.get("username");
        String password = formMap.get("password");
        return new UsernamePasswordAuthenticationToken(username, password);
    }
}

把ServerAuthenticationConverter放入AuthenticationWebFilter

 SecurityWebFilterChain chain = http.build();
        Iterator<WebFilter> weIterable = chain.getWebFilters().toIterable().iterator();
        while (weIterable.hasNext()) {
            WebFilter f = weIterable.next();
            if (f instanceof AuthenticationWebFilter) {
                AuthenticationWebFilter webFilter = (AuthenticationWebFilter) f;
                //将自定义的AuthenticationConverter添加到过滤器中
                webFilter.setServerAuthenticationConverter(new FormLoginAuthenticationConverter());
            }
        }

这样登录的请求就完成了获取post请求参数,处理,登录的过程,而其他的请求则不受影响

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值