• 利用MVC的过滤器实现url的参数加密和解密


    利用MVC的过滤器实现url的参数加密和解密

     最近在与一个IOS应用做接口对接,之前一直都没有遇到什么很大的问题,但是有一天发现可以通过软件解析app的url,然后直接通过url的拼接修改接口数据,这一下使得数据的安全性和准确性都降低了,于是就想到了url加密。

     

      然后在网上查了一下url的加密算法,使用比较普遍的还是Base64的加密,但是对于如何实现加密,网上的资料确不多,可能是我搜索的关键词不对。既然没有现成的参考文件,那么就只能靠自己了。因为所有的Controller都继承一个基Controller,所以比较自然的想到在基Controller中做一些操作,由于需要在执行具体的Action之前对url中的参数进行解密处理,所以联想到了做Asp.net项目时使用的IHttpModule接口,不过MVC有个更好的功能,那就是过滤器Filter,mvc总共提供了四种默认的Filter接口,IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter,关于这四种Filter的执行时间和使用方法网络上有很多,这里就不赘述了。下面就我的摸索过程做一个说明,也供大家参考,如果大家有更好的方法,还望不吝告知。

     

      要想能够解密Url的参数,首先需要获取的HttpRequest传递过来的参数。首先创建一个Filter,我暂且命名为DecodeUrlFitler,继承至ActionFilterAttribute,这个类已经继承了IActionFilter接口,它有四个抽象方法,分别是OnActionExecuted(在action执行完后执行)、OnActionExecuting(在action执行前执行)、OnResultExecuted(在view视图渲染之后执行)、OnResultExecuting(在view视图渲染之前执行)。很明显,我们需要重写OnActionExecuting方法,在action执行之前,将url中的参数进行解密。

     

    第一步:获取Url中的查询参数

     

      获取查询参数后,如果你仔细观察,会发现Base64格式的参数有时是经过UrEncode的,所以为了之后能够准确的进行Base64的解码,我们需要将参数进行UrlDecode处理。

     

    复制代码
    public class AppActionFilter : ActionFilterAttribute
    {
      public override void OnActionExecuting( ActionExecutingContext filterContext )
      {
        HttpRequestBase bases = (HttpRequestBase) filterContext.HttpContext.Request;
        string url = bases.RawUrl.ToString().ToLower();
        //获取url中的参数     
    string queryString = bases.QueryString.ToString();
        //对获取到的参数进行UrlDecode处理
        queryString = HttpUtility.UrlDecode(queryString);
      } }
    复制代码

     

     获取参数和处理在博客园现在有很多文章都介绍了,在msdn中查看一下类型的方法,上面的代码就可以很容易写出来,比较困难的是如何将解析后的url参数替换之前的参数,然后跳转到相应的action中,然后将执行的结果返回到客户端。我在这个问题上摸索了好久,最终找到了比较好的一个方法,下面就来说说我摸到的几块石头。

     

    第二步:url的跳转

     

    第一块石头:使用RedirectResult

     

      一开始想到的是重新拼url,将解析出来的参数拼接成一个完整的url,获取url的路径可以使用HttpRequestBase的FilePath属性获取到路径,然后获取到domain,在加上解密的queryString就可以拼接成一条完整的url了。但是如果你查看浏览器的报文,会发现这其实是进行了一个url的重定向,如果这样的话,我们url加密的目的就没有实现了,url重定向,会将解密的url传递到客户端,这就让我们的url暴露了,这完全和我们的设想相反,果断放弃。

     

    第二块石头:使用IHttpHandler

     

      之后查资料时,有提到使用IhttpHandler的ProcessRequest处理web请求的。

     

    filterContext.RequestContext.HttpContext.RewritePath(url);//url为虚拟路径
    IHttpHandler httpHandler = new MvcHttpHandler();
    httpHandler.ProcessRequest(System.Web.HttpContext.Current);

     

    这样也可以达到目的,但是如果你的action参数有非string类型的,那么在执行这个方法时会报错,虽然你看不到,但是你在Global.asax.cs的Application_Error方法中使用Server.GetLastError().GetBaseException();捕获异常,你会发现类似xxxxxx方法需要的int类型的参数,但是传递过来的是string类型等等。功能虽然实现了,但是看着就是不爽,所以继续摸索下一个方案。

     

    第三块石头:使用ActionParameters修改context的参数

     

      写代码就是要要耐心,经过我漫长的摸索,我发现没有加密的url时,ActionExecutingContext的ActionParameters属性就是url的查询参数集合,是一个Dictionary<string,object>的类型;但是如果对url进行加密,ActionParameters的参数集合里面只有key,没有value,所以我就想,能不能通过修改ActionParameters里面的值,然后在带调用其父类ActionFilterAttribute的OnActionExecuting方法,话不多说,贴出实现的代码。

     

    复制代码
    //获取访问Action参数的描述,主要是参数的类型和参数名称
                 ParameterDescriptor[] pds = filterContext.ActionDescriptor.GetParameters();
     2                     
     3                     //重新填充参数
     4                     string paramName = "";
     5                     string paramValue = "";
     6                     foreach (string param in parameters)
     7                     {
     8                         paramName = param.Split('=')[0];
     9                         paramValue = HttpUtility.UrlDecode(param.Split('=')[1]);
    10                         foreach (ParameterDescriptor pd in pds)
    11                         {
    12                             if (paramName == pd.ParameterName)
    13                             {
    14                                 //判断参数的类型,如果是整形的数据,那么将参数转换成整形数据
    15                                 if (pd.ParameterType.Name.ToLower() == "int32" || pd.ParameterType.Name.ToLower() == "nullable`1")
    16                                 {
    17                                     filterContext.ActionParameters.Add(paramName, Convert.ToInt32(paramValue));
    18                                 }
    19                                 else
    20                                 {
    21                                     filterContext.ActionParameters.Add(paramName, paramValue);
    22                                 }
    23                                 break;
    24                             }
    25                         }
    26 
    27                     }
    28                 }
    29                 base.OnActionExecuting(filterContext);
    复制代码

     

     

      不过下面和大家分享一下,使用参数替换过程中遇到的问题和值得注意的几点。

     

      1、在添加参数之前,一定要先使用Clear()方法清楚默认生成的参数,不然重新添加参数时,会出现“字典中已经存在此key的值”;还有一种的方法就是遍历传递过来的参数和ActionParameters的中的参数,替换参数的值。

     

      2、第二点要注意的是参数的类型,参数的类型和名称可以通过ActionDestriptor方法获取,如果传递的参数类型与Action定义的参数类型不一致,会引发参数类型不一致的异常。

     

      3、最后要注意的可空类型的参数,如果action的参数饱含可空类型的非空类型的参数,当可空参数有值时,那么其余的所有参数都要传递,并且赋值。最简单的办法就是遍历ActionDestriptor的参数,将所有的参数都加到ActionParameters中并附上值。

     

    复制代码
    //如果饱含可空参数,那么需要不可空的并且不在请求参数列表中的参数添加到参数列表,否则会报错 
    30                     foreach (ParameterDescriptor pd in pds)
    31                     {
    32                         if (!filterContext.ActionParameters.Keys.Contains(pd.ParameterName))
    33                         {
    34                             if (pd.ParameterType.Name.ToLower() == "nullable`1")
    35                             {
    36                                 filterContext.ActionParameters.Add(pd.ParameterName, null);
    37                             }
    38                             else if (pd.DefaultValue == null)
    39                             {
    40                                 filterContext.ActionParameters.Add(pd.ParameterName, "");
    41                             }
    42                             else
    43                             {
    44                                 filterContext.ActionParameters.Add(pd.ParameterName, pd.DefaultValue);
    45                             }
    46                         }
    47                     }
    复制代码

     

     

      还有一种方法是构建路由表,不过我没有尝试过,有兴趣的可以试下。   

     

      如果大家有更好的方法和建议,欢迎更贴拍砖。

     

     

     

     

     

     

    分类: MVC

     
     
  • 相关阅读:
    python之read()方法
    python之高阶函数
    python之lambda表达式的应用
    DevExpress.XtraGrid.view.gridview 说明文
    C# SQL时间格式
    GridControl自动定位至符合条件的行
    用sql命令修改数据表
    用C#编程从数据库中读取图片数据导进Excel文件的方法(如何从数据库中读取保存的文件,直接打开,中间不保存到本地)
    DevExpress中GridControl的属性设置及动态绑定数据和全选取消全选
    C# 导出数据到Excel模板中
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3504443.html
Copyright © 2020-2023  润新知