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

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

作者: 家猪佩奇 | 来源:发表于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