如何将我的 Auth 类更改为在另一个类中使用依赖注入进行调用?

huangapple go评论68阅读模式
英文:

How can I change my Auth class to call it inside another class using dependency injection?

问题

I understand your request. Here's the translated code portion:

我在PHP中实现了一个名为`Auth`的类,负责与(外部域名)API进行身份验证,除了我的`API`类,后者负责执行对此API的所有正常POST请求。

Auth类的工作方式如下:
```php
class Auth {
    
    private $api;
    
    public function __construct() {
        $this->api = new API;
    }

    public function handleSession() {
        if (!isset($_SESSION)) {
            session_start();
        }
        
        if (!isset($_SESSION["ACCESS_TOKEN"])) {
            $_SESSION["REFERER"] = $_SERVER["PHP_SELF"];
        
            header("Location: auth.php");
            exit;
        } else {
            unset($_SESSION["REFERER"]);
        }
    }
}

它使用依赖注入与API实例一起使用。还有其他方法通过访问器访问私有API属性,例如 $this->api->getAttr();

在客户端访问每个页面的开头,我使用以下代码来检查是否已建立令牌以进行后续操作。如果没有,它将重定向到auth.php并开始身份验证过程。

$api_auth = new Auth();
$api_auth->handleSession();

但是,我想以以下更简洁的方式更改它,以便每当我处理这个API时,我只需实例化API即可访问Auth,如下所示:

$api = new API();
$api->auth->handleSession();

要在API的构造函数中添加Auth实例,以便更具封装性,但是我真的无法想出如何实现这一点,因为Auth仍然需要访问API属性来进行身份验证。

我尝试在Auth方法中添加参数,并在API中实现它们:

class Auth {
    // ...
    public function makeRequest($id, $attr) {
        // 发送请求到API
    }
    // ...
}
class API {
    // ...
    public function handleSession() {
        $this->auth->handleSession();
    }
    
    public function makeRequest() {
        $this->auth->makeRequest($this->id, $this->attr);
    }
    // ...
}

它将被实例化如下所示:

$api = new API;
$api->handleSession();

但是这实际上违反了最初创建Auth类的目的。所以我问你,我如何实现它,以便我可以像这样调用handleSession:$api->auth->handleSession();


<details>
<summary>英文:</summary>

I implemented an `Auth` class in PHP responsible for authenticating with the (external domain) API, apart from my `API` class which is responsible for doing all the normal POST requests to this API.

The class Auth works as such:
```php
class Auth {
    
    private $api;
    
    public function __construct() {
        $this-&gt;api = new API;
    }

    public function handleSession() {
        if (!isset($_SESSION)) {
            session_start();
        }
        
        if (!isset($_SESSION[&quot;ACCESS_TOKEN&quot;])) {
            $_SESSION[&quot;REFERER&quot;] = $_SERVER[&quot;PHP_SELF&quot;];
        
            header(&quot;Location: auth.php&quot;);
            exit;
        } else {
            unset($_SESSION[&quot;REFERER&quot;]);
        }
    }
}

It uses dependency injection with an API instance.
There are other methods that access private API attributes through accessors, such $this-&gt;api-&gt;getAttr();.

At the start of every page the client accesses, I use the following at the start of the page to check if a token is established to proceed. If not, it will redirect to auth.php and start the authentication process.

$api_auth = new Auth();
$api_auth-&gt;handleSession();

However, I want to change it to the following cleaner way, so whenever I'm dealing with this api, I simply instantiate API and can access Auth from it, as such:

$api = new API();
$api-&gt;auth-&gt;handleSession();

To add an Auth instance in the constructor of API, so it would be more encapsulated, however I couldn't really think about how to achieve this, since Auth would still need to access API attributes to actually authenticate.

I tried adding arguments to Auth methods and also implement them in API:

class Auth {
    // ...
    public function makeRequest($id, $attr) {
        // make request to api
    }
    // ...
}
class API {
    // ...
    public function handleSession() {
        $this-&gt;auth-&gt;handleSession();
    }
    
    public function makeRequest() {
        $this-&gt;auth-&gt;makeRequest($this-&gt;id, $this-&gt;attr);
    }
    // ...
}

And it would be instantiated as such:

$api = new API;
$api-&gt;handleSession();

However this defeats the purpose of having an Auth class in the first place. So I ask you, how can I implement it as I could call handleSession as $api-&gt;auth-&gt;handleSession();?

答案1

得分: 1

我不认为 Auth 类是必要的。你当前的设计如下:

  • 没有令牌的用户请求一个需要令牌的资源页面
  • 资源页面检测到没有令牌并重定向到 auth.php
  • 用户发起另一个请求,到达 auth.php
  • auth.php 获取令牌并将其存储在会话中
  • auth.php 将用户重定向回资源页面
  • 用户(现在有令牌了)再次请求资源页面
  • 资源页面发起 API 请求以获取资源

所有这些都可以在单个请求中完成:

  • 没有令牌的用户请求一个需要令牌的资源页面
  • 资源页面检测到没有令牌,立即获取一个,为将来的请求存储令牌
  • 资源页面使用存储的令牌发起 API 请求以获取资源

因此,我会将透明的延迟身份验证直接构建到 API 类中。透明意味着 API 类的使用者不应该管理令牌,类应该自动处理。懒惰意味着 API 类应该推迟获取令牌直到需要。

class API
{
    // 注意这是受保护的,仅在该类内部调用。
    protected function getToken(): string
    {
        if ($youHaveNoToken) {
            $token = getTokenFromApi();
            storeTokenSomewhere($token);
        }
        return getStoredToken();
    }

    public function getAttr()
    {
        $token = $this->getToken();
        // 使用令牌发起 API 请求
    }
}

如果你想使用 PHP 会话作为存储机制,你可以这样做:

    protected function getToken(): string
    {
        if (empty($_SESSION['token'])) {
            $token = // API 请求生成新令牌
            $_SESSION['token'] = $token;
        }
        return $_SESSION['token'];
    }

这样现在允许你使用任何类型的存储来存储你的令牌,无论是 Redis、数据库还是文本文件,API 的使用者都不知道。

英文:

I don't see a need for the Auth class at all. Your current design works like this:

  • user without a token makes a request to a resource page (which needs a token)
  • the resource page detects that there's no token and redirects to auth.php
  • user makes another request, to auth.php
  • auth.php gets the token and stores it in the session
  • auth.php redirects the user back to the resource page
  • user (now with a token) makes a third request, to the resource page again
  • resource page makes an API hit to get the resource

All of this could be done on a single request:

  • user without a token makes a request to a resource page (which needs a token)
  • the resource page detects that there's no token, immediately gets one, stores it for future hits
  • the resource page makes an API hit to get the resource, using the stored token

So, I'd build transparent lazy auth right into the API class. By this, I mean:

"transparent" : The programmer using the API class shouldn't have to manage tokens, the class should do it automatically. I.e., if another person was using your API class, they shouldn't even know that tokens exist.

"lazy" : The API class should defer getting a token until it needs one.

class API
{
    // Note this is protected. It&#39;s only called within this class.
    protected function getToken(): string
    {
        if ($youHaveNoToken) {
            $token = getTokenFromApi();
            storeTokenSomewhere($token);
        }
        return getStoredToken();
    }

    public function getAttr()
    {
        $token = $this-&gt;getToken();
        // make API hit with token
    }
}

If you want PHP sessions to be your storage mechanism, you might do something like this:

    protected function getToken(): string
    {
        if (empty($_SESSION[&#39;token&#39;])) {
            $token = // API hit to generate new token
            $_SESSION[&#39;token&#39;] = $token;
        }
        return $_SESSION[&#39;token&#39;];
    }

This now allows you to use any sort of storage for your tokens. You could use Redis or a database or a text file, and the consumer of the API never knows.

huangapple
  • 本文由 发表于 2023年5月17日 22:49:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76273404.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定