TypeScript设计模式:策略模式

策略模式(Strategy Pattern)是一种行为设计模式,用于定义一系列算法,让它们可以相互替换,并且算法的变化不会影响使用算法的客户端。在身份认证系统中,策略模式常用于支持多种认证方式(如JWT、Basic Auth),以实现灵活性和可扩展性。

设计模式原理

策略模式通过将变化的算法部分提取到独立的策略类中,由上下文类动态选择和执行具体策略。这样可以实现:

  • 单一职责:每个策略类只负责一种算法实现,上下文负责协调。
  • 灵活性:支持运行时切换算法,无需修改上下文代码。
  • 开闭原则:对扩展开放(新增策略),对修改关闭(上下文不变)。

在 TypeScript 中,策略模式通过接口和多态实现,确保类型安全和代码清晰。

策略模式的结构

策略模式包含以下角色:

  1. Strategy(策略接口) :定义算法的公共接口,如 authenticate()
  2. ConcreteStrategy(具体策略) :实现策略接口,提供具体算法。
  3. Context(上下文) :维护策略对象的引用,通过接口调用算法。

优点

  • 解耦合:算法与上下文分离,降低耦合度。
  • 可扩展性:新增算法只需添加新策略类。
  • 类型安全:TypeScript 的类型系统确保接口一致性。

身份认证中的策略模式

在身份认证系统中(如 Passport.js),策略模式用于支持多种认证方式。例如:

  1. JWT认证:通过验证JSON Web Token来确认用户身份。
  2. Basic Auth:通过用户名和密码进行认证。
  3. OAuth:通过第三方服务(如Google、GitHub)进行认证。

以下以身份认证为例,展示策略模式如何支持动态选择认证方式,类似 Passport.js 的机制。

TypeScript 实现示例:身份认证中的策略模式

以下是一个身份认证系统的实现,动态选择认证策略(如JWT、Basic Auth)来验证用户请求。

typescript 复制代码
// 策略接口
interface AuthStrategy {
  authenticate(credentials: any): Promise<boolean>;
  getUserInfo(): string;
}

// 具体策略:JWT 认证
class JwtStrategy implements AuthStrategy {
  async authenticate(credentials: { token: string }): Promise<boolean> {
    // 模拟 JWT 验证逻辑
    if (credentials.token.startsWith("jwt_")) {
      return true; // 假设 token 以 "jwt_" 开头表示有效
    }
    throw new Error("无效的 JWT Token");
  }

  getUserInfo(): string {
    return "JWT 用户: user@example.com";
  }
}

// 具体策略:Basic Auth 认证
class BasicAuthStrategy implements AuthStrategy {
  async authenticate(credentials: { username: string; password: string }): Promise<boolean> {
    // 模拟 Basic Auth 验证逻辑
    if (credentials.username === "admin" && credentials.password === "pass123") {
      return true;
    }
    throw new Error("无效的用户名或密码");
  }

  getUserInfo(): string {
    return "Basic Auth 用户: admin";
  }
}

// 具体策略:OAuth 认证
class OAuthStrategy implements AuthStrategy {
  async authenticate(credentials: { accessToken: string }): Promise<boolean> {
    // 模拟 OAuth 验证逻辑
    if (credentials.accessToken.startsWith("oauth_")) {
      return true; // 假设 accessToken 以 "oauth_" 开头表示有效
    }
    throw new Error("无效的 OAuth Access Token");
  }

  getUserInfo(): string {
    return "OAuth 用户: oauth_user@example.com";
  }
}

// 上下文类:认证上下文
class AuthContext {
  private strategy: AuthStrategy;

  constructor(strategy: AuthStrategy) {
    this.strategy = strategy;
  }

  setStrategy(strategy: AuthStrategy): void {
    this.strategy = strategy;
  }

  async authenticate(credentials: any): Promise<string> {
    try {
      const isAuthenticated = await this.strategy.authenticate(credentials);
      if (isAuthenticated) {
        return this.strategy.getUserInfo();
      }
      return "认证失败";
    } catch (error) {
      return `认证错误: ${(error as Error).message}`;
    }
  }
}

// 客户端代码
async function main() {
  // 创建上下文并设置 JWT 策略
  let context = new AuthContext(new JwtStrategy());
  console.log(await context.authenticate({ token: "jwt_valid_token" })); // 输出: JWT 用户: user@example.com
  console.log(await context.authenticate({ token: "invalid_token" })); // 输出: 认证错误: 无效的 JWT Token

  // 切换到 Basic Auth 策略
  context.setStrategy(new BasicAuthStrategy());
  console.log(await context.authenticate({ username: "admin", password: "pass123" })); // 输出: Basic Auth 用户: admin
  console.log(await context.authenticate({ username: "admin", password: "wrong" })); // 输出: 认证错误: 无效的用户名或密码

  // 切换到 OAuth 策略
  context.setStrategy(new OAuthStrategy());
  console.log(await context.authenticate({ accessToken: "oauth_valid_token" })); // 输出: OAuth 用户: oauth_user@example.com
}

main();

运行结果

运行以上代码,将输出:

sql 复制代码
JWT 用户: user@example.com
认证错误: 无效的 JWT Token
Basic Auth 用户: admin
认证错误: 无效的用户名或密码
OAuth 用户: oauth_user@example.com

为什么使用策略模式?

在身份认证系统中(如 Passport.js),认证逻辑因方式不同而变化(如JWT解析、Basic Auth验证、OAuth回调)。使用策略模式:

  • 动态切换:无需修改认证上下文代码,只需注入新策略。
  • 扩展性:新增认证方式(如SAML、OpenID)只需实现新策略类。
  • 可测试性:每个策略独立,便于单元测试。

其他适用场景

虽然本示例聚焦身份认证,策略模式在认证系统中还可用于:

  • 令牌解析:不同类型的令牌(如JWT、API Key)使用不同解析逻辑。
  • 权限检查:根据用户角色或认证方式应用不同权限验证规则。
  • 日志记录:不同认证方式记录不同格式的日志。

总结

策略模式在身份认证系统中通过封装可互换的认证算法(如JWT、Basic Auth、OAuth),提供了动态选择和扩展机制。TypeScript 的类型系统确保策略接口的一致性,而认证上下文的示例展示了如何通过策略模式实现灵活的认证逻辑。这使得系统能够轻松适应多种认证需求,同时保持代码的可维护性和扩展性。

相关推荐
小白64021 分钟前
前端梳理体系从常问问题去完善-框架篇(react生态)
前端·css·html·reactjs
Hy行者勇哥1 分钟前
数据中台的数据源与数据处理流程
大数据·前端·人工智能·学习·个人开发
JarvanMo9 分钟前
Riverpod 3.0 关键变化与实战用法
前端
二十雨辰18 分钟前
vite与ts的结合
开发语言·前端·vue.js
我是日安21 分钟前
从零到一打造 Vue3 响应式系统 Day 25 - Watch:清理 SideEffect
前端·javascript·vue.js
岁月宁静22 分钟前
AI 时代,每个程序员都该拥有个人提示词库:从效率工具到战略资产的蜕变
前端·人工智能·ai编程
小高00722 分钟前
🤔「`interface` 和 `type` 到底用哪个?」——几乎每个 TS 新手被这个选择灵魂拷问。
前端·javascript·typescript
行走在顶尖24 分钟前
代码管理
前端
CodeLiving25 分钟前
使用Funasr部署语音识别websockt案例
后端
天天摸鱼的java工程师26 分钟前
Java 版 “国庆头像生成器”:8 年老开发的实用小工具
java·后端