换个角度理解设计模式之动态构建检查方法

系列文章的目录:https://blog.csdn.net/hjkl950217/article/details/89490709


记住:设计模式 重理解,轻照搬

目标

从这期文章开始,我会把每一篇文章想要达到的目标写在最前面,供您参考。

在一个检查类的内部,实现按不同的业务要求快速动态的构建检查方法,在C#中也就是委托。

知识要求

C#:懂C#中的委托、通Func这个预定义委托
Java:懂语法、懂接口定义和使用
其他:懂建造者模式的核心思想

背景

在近期的一个项目中我们需要做单点登录,除开登录服务、前端验证、分布式session的实现以前,还需要在程序中对每个API进行验证,Token编码使用JWT的方式。按我们的要求,需要在程序中实现4到5个检查点。其中还用到了多平台,平台代码需要从前端传递,程序中同样需要检查这一点。

目前要检查的点(API上有开启认证标签):

  1. 是否传递认证头
  2. 是否传递平台代码
  3. 认证头中的token值解码失败
  4. Token解码出来之后,sessionID为空或空字符串
  5. sessionID在分布式session网络中是否有效

以上5个点有一个检查不过,都会报401错误,并且在响应头中告诉它为什么。
认证流程中当然不止上面5个点,但其他的部分会由另一个认证框架来实现,这里我们就控制不到了。

分析问题

上面5个点都是必须验证通过的,不存在有某个需求后可以跳过后面的步骤,所以不考虑执行顺序
另外一点,以后有没有添加新的认证需求呢?比如加入IP黑白名单?不使用JWT,使用别的传输方式?强制下线?

所以这里我的设计思路是:

  1. 在执行时调用一个方法来完成认证
  2. 这个方法中调用不同的检查委托来认证
  3. 检查委托是通过Func<T1,T2>这种模式添加到一个集合中的, 2中的检查方法只是遍历这个集合

前面我们知道建造者模式是为了动态的去构建一个对象。那么在现在这个业务场景中,能不能把检查方法看成我们要构建的对象呢?我认为是可以的。 因为检查方法主要是遍历Func这个集合,那么让向集合添加检查委托这一步动态起来就好了。

核心代码

1.定义最后调用的东西
2.编写添加子检查的代码
3.构造方法中控制调用那些子检查。

定义检查委托集合

首先,会定义一个检查委托集合,检查方法会遍历执行它。

  private readonly List<Func<HttpContext, BizValidationError>> ChecFunckList;//BizValidationError是我们自定义的一个错误消息类,你也可以用你的

调用:

                foreach (var item in this.ChecFunckList)
                {
                    BizValidationError validationError = item(httpContext);

                    if (validationError != null)
                    {
                        httpContext.Response.Headers["YourHeaderName"] = validationError.ErrorMessage;
                        return validationError.CustomObject as IActionResult;
                    }
                }

编写子委托的代码

以检查平台为例:

        public void AddPlatformCodeCheckFun()
        {
            Func<HttpContext, BizValidationError> checkFunc = t =>
            {
                string platformCode = t.Request.Headers["PlatformCode"];

                if(platformCode==null|| platformCode.Length == 0)
                {
                    return new BizValidationError()
                    {
                        CustomObject = new UnauthorizedResult(),//需求中提到没传平台也当未认证处理
                        ErrorMessage = $"PlatformCode error"
                    };
                }
                else
                {
                    return null
                }

            };
        }

构造方法中控制调用那些检查

        public AuthorizeAttribute()
        {
            // 1.初始化对象
            this.ChecFunckList = new List<Func<HttpContext, BizValidationError>>();
            // 2.在这里控制添加了那些检查
            this.AddPlatformCodeCheckFun();
            
            //下面的方式与上面类似,只是具体代码不一样,就没有再列出来了
            this.AddJwtTokenExistFunc();
            this.AddRedisValueExistFunc();
            this.AddSessionIdExistFunc();

        }

动态的关键点

关键点在于检查集合中的内容,是动态添加的。只要控制了这点,不管你怎么玩,都能很轻松的实现目标。

Java中怎么写?

C#中是利用委托来实现,而java中不像C#中有那样灵活的委托、内部方法这些,只能使用抽象或接口来实现了。

编写逻辑:定义抽象检查方法->多个子类实现->有一个地方统一向检查集合中添加这些子类实例

真-动态

核心就在于怎么让检查集合获得这些委托,或者说“什么情况下添加什么委托”。 这一点我们可以使用配置文件或配置系统实现了。

例:代码中默认添加所有的逻辑进去,但是会按配置是否跳过这个检查

        public AuthorizeAttribute()
        {
            // 1.初始化对象
            this.ChecFunckList = new List<Func<HttpContext, BizValidationError>>();
            // 2.在这里控制添加了那些检查
            this.AddPlatformCodeCheckFun();
            
            //下面的方式与上面类似,只是具体代码不一样,就没有再列出来了
            this.AddJwtTokenExistFunc();
            this.AddRedisValueExistFunc();
            this.AddSessionIdExistFunc();
            //按配置动态添加
            if(config.CheckIp)
            {
                 this.AddIpCheckFunc();
            }

        }

还有其它的玩法,随便怎么玩~

总结

文章核心思想就是让我们的逻辑像变量一样动态的增加进去。这一点和建造者模式的思想是比较类似的,我这里也是从建造者模式中得到启发的。 我这个业务场景中不存在要跳逻辑的情况,如果有,更应该使用责任链模式一些。

如果大家有更好的想法,欢迎在下面留言讨论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值