> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 哈希（Hashing）

> 介绍如何使用 Laravel 的 Hash 门面进行安全的密码哈希与校验，涵盖 bcrypt 与 Argon2 算法的设置和用法。

## 什么是哈希

哈希（Hashing）指的是通过一种单向变换将明文数据（如密码）转换为定长字符串的处理方式。
相同输入总能生成相同的哈希，但无法通过哈希还原出原始明文。

Laravel 的 `Hash` 门面支持 **bcrypt** 和 **Argon2** 两种哈希算法，用于安全地保存密码。

### 算法对比

| 算法           | 特点                             | 推荐用途           |
| ------------ | ------------------------------ | -------------- |
| **bcrypt**   | 可通过工作因子（rounds）调整计算成本，默认算法     | 常规 Web 应用      |
| **argon2i**  | 可调整内存、时间、线程数，能抵御旁路攻击           | 对安全性要求较高的场景    |
| **argon2id** | argon2i 与 argon2d 的混合，PHC 官方推荐 | 新项目使用 Argon2 时 |

<Info>
  bcrypt 的「工作因子」用于控制生成哈希所需的时间。哈希越慢，抵御暴力破解的能力就越强。随着硬件性能提升，只要相应地增加工作因子即可保持安全等级。
</Info>

### 哈希与校验流程

```mermaid theme={null}
flowchart LR
    A[明文密码] -->|Hash::make| B["哈希值<br>存入数据库"]
    C[登录时输入] -->|Hash::check| D{匹配?}
    B --> D
    D -->|true| E[认证成功]
    D -->|false| F[认证失败]
```

***

## 配置

Laravel 默认使用 `bcrypt` 驱动。可以通过 `HASH_DRIVER` 环境变量修改。

```ini theme={null}
# .env
HASH_DRIVER=bcrypt  # bcrypt / argon / argon2id
```

要自定义哈希配置，可以通过 `config:publish` 发布配置文件。

```shell theme={null}
php artisan config:publish hashing
```

发布后可在 `config/hashing.php` 中修改默认的工作因子等。

***

## 基本用法

### 对密码进行哈希

将密码明文传入 `Hash::make()` 就会返回哈希值。请将该哈希值保存到数据库。

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class PasswordController extends Controller
{
    public function update(Request $request): RedirectResponse
    {
        $request->validate([
            'password' => ['required', 'min:8', 'confirmed'],
        ]);

        $request->user()->fill([
            'password' => Hash::make($request->password),
        ])->save();

        return redirect('/profile');
    }
}
```

<Warning>
  只将哈希值保存到数据库，绝不要保存明文密码。
</Warning>

### 调整 bcrypt 的工作因子

通过 `rounds` 选项可调整生成哈希的计算成本。值越大越安全，但耗时也会增加。
默认值（12）在多数应用场景下都足够。

```php theme={null}
$hashed = Hash::make('plain-text-password', [
    'rounds' => 14,
]);
```

### 调整 Argon2 的参数

使用 Argon2 时，可通过 `memory`、`time`、`threads` 选项调整计算成本。

```php theme={null}
$hashed = Hash::make('plain-text-password', [
    'memory'  => 65536, // KiB
    'time'    => 4,
    'threads' => 2,
]);
```

| 选项        | 说明          | 默认值   |
| --------- | ----------- | ----- |
| `memory`  | 使用的内存量（KiB） | 65536 |
| `time`    | 迭代次数        | 4     |
| `threads` | 使用的线程数      | 1     |

<Tip>
  Argon2 参数的详细信息请参阅 [PHP 官方文档](https://secure.php.net/manual/en/function.password-hash.php)。
</Tip>

***

## 校验密码

使用 `Hash::check()` 可以判断明文密码是否与已保存的哈希匹配。
这是登录处理中最典型的用法。

```php theme={null}
use Illuminate\Support\Facades\Hash;

if (Hash::check($request->password, $user->password)) {
    // 密码匹配
} else {
    // 密码不匹配
}
```

如果使用 `Auth::attempt()`，Laravel 会自动进行这一处理，不需要你直接调用。
`Hash::check()` 适合手动校验当前密码的场合。

```php theme={null}
// 在修改密码表单中确认当前密码的例子
if (! Hash::check($request->current_password, $request->user()->password)) {
    return back()->withErrors(['current_password' => '当前密码不正确。']);
}
```

***

## 是否需要重新哈希

`Hash::needsRehash()` 可以判断哈希生成时的工作因子是否与当前配置不同。
在调整了工作因子后，可以用它来更新既有哈希。

```php theme={null}
use Illuminate\Support\Facades\Hash;

if (Hash::needsRehash($user->password)) {
    $user->update([
        'password' => Hash::make($plainTextPassword),
    ]);
}
```

下面是登录成功时进行重新哈希的例子。

```mermaid theme={null}
flowchart TD
    A[登录成功] --> B{needsRehash?}
    B -->|true| C[使用新的工作因子<br>重新哈希并保存]
    B -->|false| D[继续正常流程]
    C --> D
```

```php theme={null}
// 在登录处理中执行重新哈希
if (Auth::attempt($credentials)) {
    if (Hash::needsRehash(Auth::user()->password)) {
        Auth::user()->update([
            'password' => Hash::make($credentials['password']),
        ]);
    }

    return redirect()->intended('/dashboard');
}
```

<Tip>
  随着硬件性能提升，请定期审查工作因子以保持安全性。利用 `needsRehash()`，可以在用户登录的自然时机顺便更新密码哈希。
</Tip>

***

## 哈希算法校验

默认情况下，`Hash::check()` 会验证哈希是否由当前配置的算法生成。
如果算法不同则会抛出 `RuntimeException`。

这可以防止篡改哈希算法所带来的攻击。

在需要同时支持多种算法（例如算法迁移期间）时，可以将 `HASH_VERIFY` 设置为 `false` 来禁用该校验。

```ini theme={null}
# .env
HASH_VERIFY=false
```

<Warning>
  设置 `HASH_VERIFY=false` 将禁用算法校验。请只在迁移期间使用，迁移完成后请恢复为 `true`（默认值）。
</Warning>

***

## 小结

| 想做的事       | 方法                           |
| ---------- | ---------------------------- |
| 对密码进行哈希    | `Hash::make($password)`      |
| 校验哈希       | `Hash::check($plain, $hash)` |
| 判断是否需要重新哈希 | `Hash::needsRehash($hash)`   |
| 修改哈希驱动     | 使用 `HASH_DRIVER` 环境变量        |
| 关闭算法校验     | 设置 `HASH_VERIFY=false`       |

## 下一步

<Card title="认证入门" icon="lock" href="/zh/authentication">
  学习使用 `Hash::check()` 实现登录处理等，了解认证的整体流程。
</Card>


## Related topics

- [Laravel 10 升级到 11](/zh/blog/upgrade-10-to-11.md)
- [Core —— AT Protocol 核心操作](/zh/packages/laravel-bluesky/core.md)
- [加密（Encryption）](/zh/encryption.md)
- [GitHub Actions 的固定与安全](/zh/advanced/github-actions-pinning.md)
- [Eloquent 自定义类型转换](/zh/advanced/eloquent-casts.md)
