FRP进行端口转发访问web服务

利用Frp进行端口转发详细操作

服务器部署Frps

下载运行

  • 下载frp可执行包
wget https://github.com/fatedier/frp/releases/download/v0.32.0/frp_0.32.0_linux_amd64.tar.gz
  • 解压
tar zxf frp_0.32.0_linux_amd64.tar.gz
  • 进入文件
cd frp_0.32.0_linux_amd64/
  • 修改配置文件frps.ini为如下内容
[common]
# frps与frpc通讯的端口
bind_port = 7000

# http请求监听的端口
vhost_http_port = 8888

# dashboard的用户名密码以及端口
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = 123456

# XXX.com,和*.XXX.com都必须可以解析到本服务器IP
subdomain_host = XXX.com
  • 启动
./frps -c frps.ini 

开机自启服务

  • 创建后台启动模版
vi /etc/systemd/system/frp.service
  • frp.service内容如下:
[Unit]
Description=frps
After=network.target

[Service]
ExecStart=/root/frp_0.32.0_linux_amd64/frps -c /root/frp_0.32.0_linux_amd64/frps.ini 

[Install]
WantedBy=multi-user.target
  • 启动测试
systemctl start frp.service
  • 查看启动状态
systemctl status frp.service
  • 开机自启
systemctl enable frp.service

客户端(采集端工控机)部署Frpc

下载运行

从https://github.com/fatedier/frp/releases下载windows版本包frp_0.32.0_windows_amd64.zip

  • 修改Frpc.ini如下
[common]
#服务器IP,域名也可以
server_addr = 123.45.67.89
server_port = 7000

[Test1]
type = http
local_port = 12345
# 二级域名名称
subdomain = test1
# 使用压缩
use_compression = true 

[Test2]
type = http
local_port = 12346
subdomain = test2
use_compression = true
  • 在Frpc.exe所在文件夹,cmd进入命令行
frpc -c .\frpc.ini

出现start proxy success就表示已经连接成功,此时任何发往http://test1.XXX.com:8888的请求会转发至12345端口,http://test2.XXX.com:8888的请求会发往12346端口

采集端区分请求来源

请求分类

  1. 来自端口转发的请求

    Frp转发Http请求时,会在headers中加入一个header:X-Forwarded-For,值就是该请求来源的真实IP

  2. 局域网内的请求

    此类请求可直接从HttpContext中获取IP

  3. 本地请求

    此类请求的IP为127.0.0.1,localhost,::1

过滤器

设计一个过滤器,为涉及到修改的Action打上过滤IP的标签.具体逻辑如下:

  • 先设计一张IP白名单

  • 判断headers中有没有X-Forwarded-For,有的话直接拦截.

  • 判断IP在不在白名单内,不在白名单内直接拦截.

过滤器代码如下:

public class HttpRequestIPFilterAttribute : ActionFilterAttribute
    {
        private ILogger logger;
        private readonly SystemService systemService;

        public HttpRequestIPFilterAttribute(ILogger<HttpRequestIPFilterAttribute> logger, SystemService systemService)
        {
            this.logger = logger;
            this.systemService = systemService;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var headers = context.HttpContext.Request.Headers;
            if (headers.ContainsKey("X-Forwarded-For"))
            {
                //请求来自端口转发
                logger.LogWarning("检测到远程IP的访问,IP地址:{0}", headers["X-Forwarded-For"]);
                var rspmsg = new RspMsg<string>
                {
                    Code = 401,
                    Msg = "远程请求无法调用此方法",
                    Data = null,
                };
                context.Result = new OkObjectResult(rspmsg);
                return;
            }
            else
            {
                //请求不是转发来的
                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
                var isWhite=systemService.WhiteIPList.Contains(remoteIp.ToString());
                if (!isWhite)
                {
                    logger.LogWarning("检测到白名单外的IP访问,IP地址:{0}", remoteIp.ToString());

                    var rspmsg = new RspMsg<string>
                    {
                        Code = 401,
                        Msg = "非白名单内的IP无法调用此方法",
                        Data = null,
                    };
                    context.Result = new OkObjectResult(rspmsg);
                    return;
                } 
            }
        }

注册过滤器:

services.AddScoped<HttpRequestIPFilterAttribute>();

在action中使用过滤器

    /// <summary>
    /// 获取所有报警项目
    /// </summary>
    /// <returns></returns>
    [HttpGet("v1")]
    [ServiceFilter(typeof(HttpRequestIPFilterAttribute))]  //使用过滤器
    public RspMsg<IEnumerable<AlarmItem>> GetAll()
    {
        var alarmItems = alarmService.GetAllItems();
        return RspMsg<IEnumerable<AlarmItem>>.Success(alarmItems);
    }

在远程请求时会返回:

局域网内白名单外:

本地或者白名单内:

posted @ 2020-04-13 11:21  EngCM  阅读(3249)  评论(0编辑  收藏  举报