springboot使用smiley-http-proxy-servlet作为代理,进行请求转发,可以转发前对请求路径进行调整,添加鉴权等操作~

背景: 


     从oss下载文件需要做鉴权,直接从oss获取文件流,再返回前端性能不行,所以要实现请求转发,并且能够在转发前进行鉴权,调整路径等操作,使用了smiley-http-proxy-servlet,废话不多说,直接开始:

maven依赖 

添加maven依赖:
 

<dependency>
  <groupId>org.mitre.dsmiley.httpproxy</groupId>
  <artifactId>smiley-http-proxy-servlet</artifactId>
  <version>1.11</version>
</dependency>

代理 

编写自定义代理,重写代理转发方法:如果不需要修改转发的逻辑,比如调整路径等,则直接在下面注册代理bean使用ProxyServlet即可,因为我自身平台的请求格式和oss请求格式不匹配,所以需要自定义代理,进行转发路径调整:

package com.caih.ep.cms.config;

import com.cms.attachment.entity.AttachmentDetailResVO;
import com.cms.attachment.manage.CmsAttachmentMng;
import com.common.file.GetByIdsReqVO;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * @Description
 * @Author Zephyr
 * @Date 2024/11/7
 **/
@Slf4j
@AllArgsConstructor
public class AttachmentProxyServlet extends ProxyServlet {

    //这里不能直接注入,需要在注册代理的时候通过构造器传进来
    private final CmsAttachmentMng cmsAttachmentMng;

    /**
     * @description: 重写代理请求地址  /ep/cms/attachment/{fileId}/{fileName}
     *                        ——> /ep/cms/attachment/ossKey?response-content-disposition=attachment; filename=fileName
     * @date: 2024/11/8
     * @param:
     * @param: servletRequest
     * @return: String
     **/
    @SneakyThrows
    @Override
    protected String rewritePathInfoFromRequest(HttpServletRequest servletRequest) {
        String pathInfo = servletRequest.getPathInfo();

        //提取文件id
        String fileId = pathInfo.substring(1, pathInfo.lastIndexOf("/"));

        // 提取文件名
        String fileName = pathInfo.substring(pathInfo.lastIndexOf("/") + 1);

        //查询附件详情,获取ossKey
        AttachmentDetailResVO attachmentDetailResVO = cmsAttachmentMng.getDetailByFileId(fileId);
        String ossKey = attachmentDetailResVO.getMongoFileId();

        // 编码文件名,防止特殊字符导致的问题
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());

        // 修改路径,移除 / 后缀,并添加查询参数
        String targetPath = "/" + ossKey + "?response-content-disposition=attachment; filename=" + encodedFileName;
//        log.info("oss文件请求地址:" + pathInfo + " ——> " + targetPath);
        return targetPath;
    }


}

注册代理bean:

package com.caih.ep.cms.config;

import com.cms.attachment.manage.CmsAttachmentMng;
import com.google.common.collect.ImmutableMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

/**
 * @Description
 * @Author Zephyr
 * @Date 2024/11/7
 **/
@Configuration
public class ProxyConfig {

    //oss的域名
    @Value("${oss.config.domain}")
    private String ossDomain;

    //业务处理service
    @Autowired
    private CmsAttachmentMng cmsAttachmentMng;

    /**
     * @description: 附件下载代理
     * @date: 2024/11/8
     * @param:
     * @return: ServletRegistrationBean
     **/
    @Bean
    public ServletRegistrationBean proxyServletRegistration(){
        //需要代理的转发路径前缀
        String servletPath = "/ep/cms/attachment/*";
        //需要转发到的目标地址
        String targetUri = ossDomain;
        //这里构造器new 的是一个自己自定义的ProxyServlet,如果不需要在转发的时候做转发逻辑,则这里可以直接new ProxyServlet()即可
        ServletRegistrationBean registrationBean= new ServletRegistrationBean(new AttachmentProxyServlet(cmsAttachmentMng), servletPath);
        //这个setName有多个的时候,名字需要不一样
        registrationBean.setName("attachmentProxy");
        //设置网址以及参数
        Map<String, String> params = ImmutableMap.of(
                "targetUri", targetUri,
                "log", "true");
        registrationBean.setInitParameters(params);
        return registrationBean;
    }
}

 这里实现了从/ep/cms/attachment/**转发到ossDomain/**:
eg:/ep/cms/attachment/aaa/bbb.pdf ==>  ossDomain/aaa/bbb.pdf

到这里转发的代码就写完了,想要在转发前做鉴权怎么做呢?其实在自定义的代理Servlet里面是可以做的,但是一般不推荐,转发代理只处理代理的逻辑。我们这里使用过滤器实现。

注意:不能使用拦截器,因为请求是先到过滤器—>代理—>拦截器 ,请求还未到拦截器就已经转发到文件服务器了

过滤器 鉴权

创建过滤器:

package com.cms.filters;

import com.attachment.manage.CmsAttachmentMng;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import java.io.IOException;

/**
 * @Description 文件鉴权过滤器
 * @Author Zephyr
 * @Date 2024/11/7
 **/
@Slf4j
@AllArgsConstructor
public class FileFilter implements Filter {

    private final CmsAttachmentMng cmsAttachmentMng;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 

        //文件鉴权逻辑


        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }
}

鉴权逻辑就不展示了,在doFilter方法里面进行鉴权,不通过可以直接抛出异常,直接return 

注册过滤器

package com.caih.ep.cms.filters;

import com.cms.attachment.manage.CmsAttachmentMng;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

@Configuration
public class ServerFilterConfig {

  @Autowired
  private CmsAttachmentMng cmsAttachmentMng;

  @Bean
  public FilterRegistrationBean authFilterRegistration(){
    FilterRegistrationBean registration = new FilterRegistrationBean();
    //添加过滤器
    registration.setFilter(new FileFilter(cmsAttachmentMng));
    //设置过滤路径
    registration.addUrlPatterns("/ep/cms/attachment/*");
    registration.setName("fileFilter");
    //设置优先级
    registration.setOrder(0);
    return registration;
  }

}

至此,大功告成!

smiley-http-proxy-servlet是一个基于Java代理服务器,可以用于转发请求并修改响应。要创建Proxy Servlet并修改cookie,您可以按照以下步骤进行: 1. 创建一个新的Java类并继承ProxyServlet类。 2. 重写doFilter方法,在方法中获取请求的cookie并进行修改,然后将请求转发给目标服务器。 3. 重写getProxyHost和getProxyPort方法,指定目标服务器的主机和端口。 4. 在web.xml文件中配置Servlet映射,使得请求能够正确地被代理Servlet处理。 下面是一个简单的示例代码,演示如何创建一个Proxy Servlet并修改cookie: ``` public class MyProxyServlet extends ProxyServlet { @Override protected void doFilter(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 获取请求的cookie Cookie[] cookies = servletRequest.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("myCookie")) { // 修改cookie cookie.setValue("newCookieValue"); servletResponse.addCookie(cookie); } } } // 转发请求给目标服务器 super.doFilter(servletRequest, servletResponse, filterChain); } @Override protected String getProxyHost(HttpServletRequest servletRequest) { // 指定目标服务器的主机 return "mytargetserver.com"; } @Override protected int getProxyPort(HttpServletRequest servletRequest) { // 指定目标服务器的端口 return 80; } } ``` 在web.xml文件中添加以下配置: ``` <servlet> <servlet-name>MyProxyServlet</servlet-name> <servlet-class>com.example.MyProxyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyProxyServlet</servlet-name> <url-pattern>/proxy/*</url-pattern> </servlet-mapping> ``` 以上示例代码仅供参考,具体实现需要根据您的具体需求进行调整
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值