You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中使用自定义HASHBYTES('md5')实现登录?

基于HASHBYTES('MD5')实现Laravel登录的优化方案

方案一:重写User模型的密码验证方法

Laravel的认证系统会自动调用模型的validateCredentials方法做密码校验,我们直接重写这个方法,适配HASHBYTES('MD5')的规则即可,无需重复查询数据库:

  1. 修改User模型代码:
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Support\Facades\DB;

class User extends Authenticatable
{
    // 保留原有模型属性与方法

    /**
     * 验证输入密码与数据库存储的哈希是否匹配
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(AuthenticatableContract $user, array $credentials)
    {
        $inputPassword = $credentials['PASSWORD'];
        // 调用数据库HASHBYTES生成哈希,与数据库存储值对比
        $computedHash = DB::selectOne("SELECT HASHBYTES('MD5', ?) AS hashed", [$inputPassword])->hashed;
        
        // 使用hash_equals避免时序攻击
        return hash_equals($user->PASSWORD, $computedHash);
    }
}
  1. 简化登录控制器代码:
    直接用Laravel Auth的attempt方法完成认证,不用自己写两次查询:
public function masuk(Request $request)
{
    $this->validate($request, [
        'USERNAME_ACC' => 'required',
        'PASSWORD' => 'required'
    ]);

    $credentials = [
        'USERNAME_ACC' => $request->USERNAME_ACC,
        'PASSWORD' => $request->PASSWORD // 直接传明文,模型会自动处理哈希验证
    ];

    if (Auth::guard('web')->attempt($credentials)) {
        return redirect()->intended('admin');
    }

    return redirect('/login')->with('gagal', 'Username or Password Not Register');
}

方案二:自定义哈希驱动(适配全场景)

如果需要在用户注册、密码重置等场景也统一使用HASHBYTES('MD5'),可以自定义哈希驱动,更符合Laravel的生态规范:

  1. 创建自定义哈希驱动类
    在app/Providers/Hash目录下新建HashBytesMd5Driver.php(目录不存在则手动创建):
namespace App\Providers\Hash;

use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Support\Facades\DB;

class HashBytesMd5Driver implements Hasher
{
    /**
     * 生成密码哈希
     *
     * @param  string  $value
     * @param  array  $options
     * @return string
     */
    public function make($value, array $options = [])
    {
        return DB::selectOne("SELECT HASHBYTES('MD5', ?) AS hashed", [$value])->hashed;
    }

    /**
     * 验证明文与哈希是否匹配
     *
     * @param  string  $hashedValue
     * @param  string  $value
     * @param  array  $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = [])
    {
        if (empty($hashedValue)) return false;
        
        $computedHash = $this->make($value);
        return hash_equals($hashedValue, $computedHash);
    }

    /**
     * 检查哈希是否需要重新生成(MD5无需重哈希,返回false)
     *
     * @param  string  $hashedValue
     * @param  array  $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = [])
    {
        return false;
    }
}
  1. 注册自定义驱动
    修改config/hashing.php配置文件,添加自定义驱动:
return [
    'default' => env('HASH_DRIVER', 'hashbytesmd5'), // 可设为默认驱动,或保持原驱动按需指定

    'drivers' => [
        // 保留原有驱动(bcrypt/argon2等)
        'hashbytesmd5' => [
            'driver' => 'hashbytesmd5',
        ],
    ],
];
  1. 在服务提供者中绑定驱动
    修改app/Providers/AppServiceProvider.php的boot方法:
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Hashing\HashManager;
use App\Providers\Hash\HashBytesMd5Driver;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app->make(HashManager::class)->extend('hashbytesmd5', function ($app) {
            return new HashBytesMd5Driver();
        });
    }
}
  1. 实际使用
  • 注册用户时生成哈希:
$user = new User();
$user->USERNAME_ACC = $request->USERNAME_ACC;
$user->PASSWORD = \Hash::driver('hashbytesmd5')->make($request->PASSWORD);
$user->save();
  • 登录验证(也可复用方案一的模型重写方式,或直接在控制器中调用):
public function masuk(Request $request)
{
    $this->validate($request, [
        'USERNAME_ACC' => 'required',
        'PASSWORD' => 'required'
    ]);

    $user = User::where('USERNAME_ACC', $request->USERNAME_ACC)->first();

    if ($user && \Hash::driver('hashbytesmd5')->check($request->PASSWORD, $user->PASSWORD)) {
        Auth::guard('web')->login($user);
        return redirect()->intended('admin');
    }

    return redirect('/login')->with('gagal', 'Username or Password Not Register');
}

关键注意事项

  • 数据库PASSWORD字段类型建议设为VARBINARY(16)或BINARY(16),因为HASHBYTES('MD5')生成的是二进制哈希值,用字符串类型存储可能出现编码问题导致验证失败。
  • MD5属于弱哈希算法,安全性极低,若为新项目强烈建议使用Laravel默认的Bcrypt/Argon2算法;若为遗留系统必须使用MD5,建议添加固定盐值(比如在HASHBYTES中拼接用户ID或固定字符串)提升安全性。

内容的提问来源于stack exchange,提问作者Hasun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:56:25