首先,我们需要定义一个抽象的认证接口,所有的具体认证策略都将实现这个接口。
interface AuthStrategyInterface {
public function authenticate($credentials);
}
接下来,为每种认证方式创建具体的策略类。
class PasswordAuthStrategy implements AuthStrategyInterface { private $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function authenticate($credentials) { // 假设 $credentials 是一个关联数组 ['username' => ..., 'password' => ...] $user = $this->userService->getUserByUsername($credentials['username']); if ($user && password_verify($credentials['password'], $user->getPasswordHash())) { return $user; // 返回用户对象表示认证成功 } throw new AuthenticationException('Invalid credentials'); } }
class TokenAuthStrategy implements AuthStrategyInterface { private $tokenService; public function __construct(TokenService $tokenService) { $this->tokenService = $tokenService; } public function authenticate($credentials) { // 假设 $credentials 是一个字符串 token $user = $this->tokenService->validateToken($credentials); if ($user) { return $user; // 返回用户对象表示认证成功 } throw new AuthenticationException('Invalid token'); } }
最后,我们需要一个上下文类来管理这些策略,并提供一个统一的方法来进行认证。
class AuthContext { private $strategy; public function setStrategy(AuthStrategyInterface $strategy) { $this->strategy = $strategy; } public function authenticate($credentials) { if (!$this->strategy) { throw new Exception('Authentication strategy not set'); } return $this->strategy->authenticate($credentials); } }
现在可以在应用的不同部分根据需要切换认证策略。
// 设置密码认证策略并尝试认证 $authContext = new AuthContext(); $authContext->setStrategy(new PasswordAuthStrategy($userService)); try { $user = $authContext->authenticate(['username' => 'john', 'password' => 'secret']); echo "Password authenticated: " . $user->getName(); } catch (AuthenticationException $e) { echo $e->getMessage(); } // 设置 Token 认证策略并尝试认证 $authContext->setStrategy(new TokenAuthStrategy($tokenService)); try { $user = $authContext->authenticate('valid_token_string'); echo "Token authenticated: " . $user->getName(); } catch (AuthenticationException $e) { echo $e->getMessage(); }
总结
在这个例子中,我们展示了如何利用策略模式来处理不同类型的用户认证方式。这样做有几个好处:
灵活性:可以通过简单地更改上下文中的策略来轻松添加或移除新的认证方式。
可扩展性:新加入的认证方式只需实现 AuthStrategyInterface 即可,无需修改现有代码。
单一职责原则:每个策略类只负责一种特定的认证逻辑,使得代码更易于理解和维护。