zoukankan      html  css  js  c++  java
  • 如何编写一个Fiddler扩展

    如何编写一个Fiffler扩展

    需求

    起因1

    因为开发需要,需要使用test环境的网页直连我的开发电脑进行调试.

    解决方案1

    直接使用FiddlerAutoResponder功能实现.

    起因2

    调试过程中发现,将请求转发到我的开发电脑后,服务无法获取用户信息.
    经追踪发现,前端所有请求是通过网关传递到后方的微服务中的,包含用户信息的Cookie经过网关转换为另一个请求头.此请求头中的信息才是微服务识别的用户信息.
    同时,这也导致了使用AutoResponder无法正确传递用户信息,本地服务无法获取用户信息.

    解决方案2

    经过调研,决定使用FiddlerExtend(扩展),完成如下功能

    • 在指定请求前,插入额外请求获取用户信息,并将其以指定格式配装到原有请求中
    • 指定请求通过正则对url进行匹配
    • 可以指定上述的额外请求的url
    • 可以动态开关此功能
    • 请求转发功能还是由AutoResponder完成
    • 有日志功能,可以捕获错误

    前置准备

    安装最新版Fiddler

    • (略)

    安装Visual Studio 2019

    • 下载Visual Studio Installer
    • 启动Visual Studio Installer
    • 在工作负载中选选择 .NET桌面开发选项
    • 调整安装文件夹,进行安装

    安装 .NET Framework 4.7.2

    • (略)

    创建项目

    1. 打开Visual Studio 2019

    2. 创建新项目

    3. 使用模板类库(.NET Framework) 作为项目模板

      注意,这里可能会有多种类库类型.如类库(.NET Core)类库(.NET Standard).注意选择正确的模板

    4. 下一步

    5. 输入项目名,选择项目位置

    6. 选择将解决方案与项目放在同一目录中(非必要)

    7. 选择框架 -> .NET Framework 4.7.2

    8. 添加Fiddler引用

      1. 右键点击项目引用
      2. 选择添加引用
      3. 选择左侧菜单中的浏览
      4. 选择右下侧的浏览按钮
      5. 选择<fiddler_home>Fiddler.exe
      6. 确定

    编写代码

    打开Class1.cs输入如下代码

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Net.Http;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Fiddler;
    
    [assembly: Fiddler.RequiredVersion("2.3.5.0")]
    
    /**
     * 进行用户信息转换
     */
    public class SsoAutoTamper : IAutoTamper
    {
        /**
         * sso服务默认url
         */
        private String default_sso_url = "<url>";
        /**
         * url正则输入框
         */
        private TextBox regularBox;
        /**
         * sso服务url输入框
         */
        private TextBox getSsoUrlBox;
        /**
         * 启动复选框
         */
        private CheckBox setupBox;
        /**
         * 日志输出框
         */
        private TextBox logBox;
        /**
         * 标题宽度
         */
        private int labelWidth = 110;
        /**
         * 标题高度
         */
        private int labelHeight = 25;
        /**
         * 输入框宽度
         */
        private int inputBoxWidth = 120;
        /**
         * 输入框高度
         */
        private int inputBoxHeight = 25;
        /**
         * OnLoad方法执行完成标志
         */
        private bool hasOnLoad;
    
        public SsoAutoTamper()
        {
        }
    
        /**
         * 加载回调,可以用于UI声明
         */
        public void OnLoad() 
        {
            // 构造table页
            TabPage tabPage = new TabPage("ssoUserTools");
            FiddlerApplication.UI.tabsViews.TabPages.Add(tabPage);
    
            // 启用按钮
            tabPage.Controls.Add(new Label
            {
                Text = "是否启用: ",
                Width = labelWidth,
                Height = labelHeight,
                TextAlign = ContentAlignment.MiddleLeft
            });
            tabPage.Controls.Add(setupBox = new CheckBox
            {
                Location = new Point(labelWidth, 0),
            });
            // 注册事件
            setupBox.CheckedChanged += CheckBoxChanged;
    
            // 正则输入框label
            tabPage.Controls.Add(new Label
            {
                Text = "目标url正则表达式: ",
                Width = labelWidth,
                Height = labelHeight,
                TextAlign = ContentAlignment.MiddleLeft,
                Location = new Point(0, labelHeight)
            });
            // 正则输入框
            tabPage.Controls.Add(regularBox = new TextBox
            {
                Width = inputBoxWidth,
                Height = inputBoxHeight,
                Location = new Point(labelWidth, labelHeight),
                Text = "<default pattern>"
            });
            // 获取用户信息url输入框label
            tabPage.Controls.Add(new Label
            {
                Text = "获取用户信息url: ",
                Width = labelWidth,
                Height = labelHeight,
                TextAlign = ContentAlignment.MiddleLeft,
                Location = new Point(0, labelHeight * 2)
            });
            tabPage.Controls.Add(getSsoUrlBox = new TextBox
            {
                Width = inputBoxWidth,
                Height = inputBoxHeight,
                Location = new Point(labelWidth, labelHeight*2),
                Text = default_sso_url
            });
            // 日志
            tabPage.Controls.Add(logBox = new TextBox
            {
                Location = new Point(0, labelHeight * 3),
                Width = 300,
                Height = 200,
                Multiline = true
            });
    
            hasOnLoad = true;
        }
        public void OnBeforeUnload() { }
    
        public void AutoTamperRequestAfter(Session oSession) { }
        public void AutoTamperResponseBefore(Session oSession) { }
        public void AutoTamperResponseAfter(Session oSession) { }
        public void OnBeforeReturningError(Session oSession) { }
    
        public void AutoTamperRequestBefore(Session oSession)
        {
            try
            {
                // OnLoad未完成,直接返回
                if(!hasOnLoad)
                {
                    return;
                }
                // 未启用直接返回
                if(!setupBox.Checked)
                {
                    return;
                }
                // 正则不匹配直接返回
                if (!Regex.IsMatch(oSession.fullUrl, regularBox.Text))
                {
                    return;
                }
    
                Log("匹配路径->" + oSession.fullUrl);
    
                // 构造请求客户端
                HttpClientHandler httpClientHandler = new HttpClientHandler();
                httpClientHandler.UseCookies = false;
                HttpClient httpClient = new HttpClient(httpClientHandler);
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, getSsoUrlBox.Text);
                // 复制所有头信息
                IEnumerator<HTTPHeaderItem> ie = oSession.oRequest.headers.GetEnumerator();
                while (ie.MoveNext())
                {
                    HTTPHeaderItem hi = ie.Current;
                    // 跳过Content相关头
                    if(hi.Name.StartsWith("Content-"))
                    {
                        continue;
                    }
                    httpRequestMessage.Headers.Add(hi.Name, hi.Value);
                }
                // 进行请求
                Task<HttpResponseMessage> response = httpClient.SendAsync(httpRequestMessage);
                HttpContent httpContent = response.Result.Content;
                Task<string> result = httpContent.ReadAsStringAsync();
                // 向原有请求头中添加用户信息
                oSession.oRequest.headers.Add("actual-user", result.Result);
            }
            catch(Exception e)
            {
                //logBox.AppendText(e.Message);
                logBox.AppendText(e.StackTrace);
                logBox.AppendText(e.Source);
            }
            return;
        }
    
        /**
         * 启动复选框回调
         */
        void CheckBoxChanged (Object sender, EventArgs eventArgs)
        {
            if (setupBox.Checked)
            {
                Log("开启sso转换功能");
            }
            else
            {
                Log("关闭sso转换功能");
            }
        }
    
        /**
         *日志方法
         */
        void Log(String text)
        {
            logBox.AppendText("
    ");
            logBox.AppendText(text);
        }
    }
    

    编译

    1. 生成 -> 生成解决方案

    2. 可以看到如下日志

      已启动生成…
      1>------ 已启动生成: 项目: <project_name>, 配置: Debug Any CPU ------
      1>  <project_name> -> <project_path><project_name>inDebug<project_name>.dll
      ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
      

    加载扩展

    1. 关闭Fiddler
    2. 复制上述日志中的 <project_name>.dllC:Userslixiaoxi_vDocumentsFiddler2Scripts
    3. 打开Fiddler
    4. 可以在Fiddler中看到声明的ssoUserTools标签,这个就是需要功能了~

    PS

    • 本人是Java开发,上述所有功能都是我一边翻Fiddler文档,一边翻C#API文档拼凑出来的.所以内容可能会有疏漏与错误,如果有的话,还请指正.
    • 代码部分为了保密,我直接在markdown编辑器中对一些代码与注释进行了修改,参考时请注意.

    参考

    Fiddler Extend
    HttpClient
    C#的正则表达式用法

    狗头

  • 相关阅读:
    面向对象
    linux下apache重启报错
    mysql登录密码忘记怎么办?
    html基础知识梳理
    用js实现贪吃蛇
    简单轮播图案例
    JavaScript基础学习笔记整理
    读书笔记之《Redis开发与运维》—— 三
    读书笔记之《Redis开发与运维》—— 二
    读书笔记之《Redis开发与运维》—— 一
  • 原文地址:https://www.cnblogs.com/heaven-elegy/p/14450991.html
Copyright © 2011-2022 走看看