django-rest-knox ライブラリのトークンのtoken_key について

### トークンを生成し、トークンの登録を確認
```
"token": "e2db80303283ee15f102789e2e7f5a4053cb774041b385a83eeab19fc6298aee"
```



### token_key は検索用のインデックスであり、ハッシュ化されていないトークンの頭文字8文字である

先ほど発行したトークンの頭文字8文字と一致していることを確認
```
token_key: e2db8030
```

# knox model の説明

```knox.models.py

class AbstractAuthToken(models.Model):

    objects = AuthTokenManager()

    digest = models.CharField(
        max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
    token_key = models.CharField(
        max_length=CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH +
        CONSTANTS.TOKEN_KEY_LENGTH,
        db_index=True
    )
    user = models.ForeignKey(User, null=False, blank=False,
                             related_name='auth_token_set', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    expiry = models.DateTimeField(null=True, blank=True)

    class Meta:
        abstract = True

    def __str__(self) -> str:
        return f'{self.digest} : {self.user}'


class AuthToken(AbstractAuthToken):
    class Meta:
        swappable = 'KNOX_TOKEN_MODEL'
```


それぞれのフィールドについて詳しく説明させていただきます：

### 1. `digest`
```python
digest = models.CharField(max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
```
- トークンのハッシュ値を保存するフィールドです
- `primary_key=True`で主キーとして設定されています
- セキュリティのため、実際のトークン値ではなく、ハッシュ化された値を保存します
- CharFieldとして定義され、長さは`CONSTANTS.DIGEST_LENGTH`で制限されています

### 2. `token_key`
```python
token_key = models.CharField(
    max_length=CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH + CONSTANTS.TOKEN_KEY_LENGTH,
    db_index=True
)
```
- トークンの識別子部分を保存するフィールドです
- `db_index=True`でインデックスが作成され、検索を高速化します
- 最大長は`MAXIMUM_TOKEN_PREFIX_LENGTH`と`TOKEN_KEY_LENGTH`の合計です
- トークンの一部を保存することで、完全な照合の前に高速なフィルタリングが可能になります

### 3. `user`
```python
user = models.ForeignKey(User, null=False, blank=False,
                        related_name='auth_token_set', 
                        on_delete=models.CASCADE)
```
- トークンの所有者であるユーザーへの外部キー参照です
- `null=False, blank=False`で必須フィールドとして設定されています
- `related_name='auth_token_set'`により、ユーザーモデルから`auth_token_set`でトークンにアクセス可能です
- `on_delete=models.CASCADE`でユーザーが削除された場合、関連するトークンも削除されます

### 4. `created`
```python
created = models.DateTimeField(auto_now_add=True)
```
- トークンが作成された日時を自動的に記録します
- `auto_now_add=True`により、レコード作成時に自動的に現在時刻が設定されます

### 5. `expiry`
```python
expiry = models.DateTimeField(null=True, blank=True)
```
- トークンの有効期限を設定するフィールドです
- `null=True, blank=True`で任意フィールドとして設定されています
- 値が設定されている場合、その日時でトークンは無効になります

このモデルは`AbstractAuthToken`として抽象クラスで定義され、実際の実装は`AuthToken`クラスで行われています。`swappable = 'KNOX_TOKEN_MODEL'`の設定により、必要に応じて独自のトークンモデルに置き換えることが可能です。


```knox.models.py
class AuthTokenManager(models.Manager):
    def create(
        self,
        user,
        expiry=knox_settings.TOKEN_TTL,
        prefix=knox_settings.TOKEN_PREFIX,
        **kwargs
    ):
        token = prefix + crypto.create_token_string()
        digest = crypto.hash_token(token)
        if expiry is not None:
            expiry = timezone.now() + expiry
        instance = super().create(
            token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH], digest=digest,
            user=user, expiry=expiry, **kwargs)
        return instance, token


```
これはDjango Knoxライブラリの認証トークンを作成するためのマネージャークラスです。詳しく説明させていただきます：

### AuthTokenManagerの機能説明

```python
def create(self, user, expiry=knox_settings.TOKEN_TTL, prefix=knox_settings.TOKEN_PREFIX, **kwargs):
```

このメソッドは以下の主要なパラメータを受け取ります：
- `user`: トークンを発行するユーザー
- `expiry`: トークンの有効期限（デフォルトは`knox_settings.TOKEN_TTL`）
- `prefix`: トークン文字列の接頭辞（デフォルトは`knox_settings.TOKEN_PREFIX`）

### 処理の流れ

1. トークンの生成：
```python
token = prefix + crypto.create_token_string()
```
- 設定された接頭辞と、暗号学的に安全な乱数文字列を組み合わせて新しいトークンを生成します

2. ダイジェストの作成：
```python
digest = crypto.hash_token(token)
```
- セキュリティのため、トークンをハッシュ化します
- このハッシュ値がデータベースに保存されます

3. 有効期限の設定：
```python
if expiry is not None:
    expiry = timezone.now() + expiry
```
- 有効期限が指定されている場合、現在時刻に指定された期間を加算します

4. トークンインスタンスの作成：
```python
instance = super().create(
    token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH],
    digest=digest,
    user=user,
    expiry=expiry,
    **kwargs
)
```
- データベースにトークン情報を保存します
- `token_key`には完全なトークンの一部のみを保存（検索用）
- `digest`にはトークン全体のハッシュ値を保存
- ユーザーと有効期限情報も保存

5. 戻り値：
```python
return instance, token
```
- データベースに保存されたトークンインスタンスと
- クライアントに送信する生のトークン文字列を返します

### セキュリティ上の特徴
- 完全なトークン文字列はデータベースに保存されません
- データベースには検索用の部分文字列（token_key）とハッシュ値（digest）のみが保存されます
- トークンの検証時には、受け取ったトークンをハッシュ化して保存されているダイジェストと比較します

参考文献：
- https://jazzband.github.io/django-rest-knox/
- [knox.models.py](https://github.com/jazzband/django-rest-knox/blob/develop/knox/models.py)