美文网首页
学习笔记-如何对接口鉴权这样一个功能开发做面相对象的分析

学习笔记-如何对接口鉴权这样一个功能开发做面相对象的分析

作者: 家猪佩奇 | 来源:发表于2020-04-01 21:07 被阅读0次

    如何进行面向对象的设计?

    我们知道,面相对象的分析产出是详细的需求描述,那面相对象设计的产出就是类。在面相对象设计环节,我们将需求描述转化为具体的类的设计。我们把这一环节拆解细化一下,主要包含以下几个部分:

    • 划分职业进而识别出有哪些类
    • 定义类及其属性和方法
    • 定义类与类之间的交互关系
    • 将类组装起来并提供执行入口

    1. 划分职责进而识别出有哪些类

    根据需求描述,把其中涉及的功能点,一个一个罗列出来,然后再去看哪些功能点职责相近,操作同样的属性,可否应该归为同一个类。我们来看一下,针对鉴权这个例子,具体该如何来做。

    先是详细的需求描述:

    • 调用方进行接口请求的时候,将 URL、AppID、密码、时间戳拼接在一起,通过加密算法生成 token,并且将 token、AppID、时间戳拼接在 URL 中,一并发送到微服务端。
    • 微服务端在接收到调用方的接口请求之后,从请求中拆解出 token、AppID、时间戳。
    • 微服务端首先检查传递过来的时间戳跟当前时间,是否在 token 失效时间窗口内。如果已经超过失效时间,那就算接口调用鉴权失败,拒绝接口调用请求。
    • 如果 token 验证没有过期失效,微服务端再从自己的存储中,取出 AppID 对应的密码,通过同样的 token 生成算法,生成另外一个 token,与调用方传递过来的 token 进行匹配。如果一致,则鉴权成功,允许接口调用;否则就拒绝接口调用。

    首先,要做的是主句阅读上面的需求描述,拆解成小的功能点,一条一条的罗列下来。注意,拆解出的每个功能点要尽可能的小。每个功能点只负责做一件很小的事情(单一职责)。得到以下功能点列表:

    1. 把URL、AppID、密码、时间戳拼接为一个字符串;
    2. 对字符串通过加密算法加密生成token;
    3. 将token、AppID、时间戳拼接到URL中,形成新的URL;
    4. 解析URL,得到token、AppID、时间戳等信息;
    5. 从存储中取出AppID和对应的密码;
    6. 根据时间戳判断token是否过期失效;
    7. 验证两个token是否匹配。

    从功能列表中我们发现,1、2、6、7都是跟token有关,负责token的生成、验证;3、4都是在处理URL,负责URL的拼接、解析;5是操作AppID和密码,负责从存储中读取AppID和密码。

    所以我们可以粗略的得到三个核心的类:AuthToken、URL、CredentialStorage。AuthToken负责实现1、2、6、7这四个操作;URL负责3、4两个操作;CredentialStorage负责5这个操作。

    2.定义类及其属性和方法。

    AuthToken相关的功能点有4个:

    • 把URL、AppID、密码、时间戳拼接为一个字符串。

    • 对字符串通过加密算法生成token;

    • 根据时间戳判断token是否过期失效;

    • 验证两个token是否匹配

    对于方法的识别,很多面相对象的书籍,一般都是这么讲的,识别出需求描述中的动词,作为候选方法,再进一步过滤筛选。类比一下方法的识别,我们可以把功能中涉及的名词,作为候选属性,然后同样进行过滤筛选。
    我们可以借鉴这个思路,识别出来AuthToken类的属性和方法。

    URL相关的功能有两个:

    • 将token、AppID、时间戳拼接到URL中,形成新的URL。

    • 解析URL,得到token、AppID、时间戳等信息。
      虽然需求描述中,我们是以URL来代替接口请求,但是接口请求并不是以URL的形式来表达,还有可能是dubbo、rpc等其他形式。为了让这个类更加通用,我们把它命名为ApiRequest。

    CredentialStorage相关功能点有一个:

    • 从存储中取出AppID和对应的密码

    这里给出一个demo仅供参考:

    public interface ApiAuthenticator {
      void auth(String url);
      void auth(ApiRequest apiRequest);
    }
    public class DefaultApiAuthenticatorImpl implements ApiAuthenticator {
      private CredentialStorage credentialStorage;
      
      public DefaultApiAuthenticator() {
        this.credentialStorage = new MysqlCredentialStorage();
      }
      
      public DefaultApiAuthenticator(CredentialStorage credentialStorage) {
        this.credentialStorage = credentialStorage;
      }
      @Override
      public void auth(String url) {
        ApiRequest apiRequest = ApiRequest.buildFromUrl(url);
        auth(apiRequest);
      }
      @Override
      public void auth(ApiRequest apiRequest) {
        String appId = apiRequest.getAppId();
        String token = apiRequest.getToken();
        long timestamp = apiRequest.getTimestamp();
        String originalUrl = apiRequest.getOriginalUrl();
        AuthToken clientAuthToken = new AuthToken(token, timestamp);
        if (clientAuthToken.isExpired()) {
          throw new RuntimeException("Token is expired.");
        }
            String password = credentialStorage.getPasswordByAppId(appId);
        AuthToken serverAuthToken = AuthToken.generate(originalUrl, appId, password, timestamp);
        if (!serverAuthToken.match(clientAuthToken)) {
          throw new RuntimeException("Token verfication failed.");
        }
    }
    

    相关文章

      网友评论

          本文标题:学习笔记-如何对接口鉴权这样一个功能开发做面相对象的分析

          本文链接:https://www.haomeiwen.com/subject/uurzuhtx.html