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

Laravel中Auth::attempt如何适配MSSQL的binary(13)类型字段

在Laravel中适配MSSQL binary(13)类型实现用户登录认证

问题背景

开发RF Online游戏网站时,MSSQL数据库中tbl_rfaccount表的id、password字段为binary(13)类型,无法修改该字段类型(否则会导致RF Launcher无法正常登录),但Laravel默认的Auth::attempt函数无法直接适配该类型,导致登录失败。

尝试过程

尝试1:直接调用Auth::attempt

直接传入用户输入的字符串调用Auth::attempt,始终返回登录失败:

$request->validate([
    'id' => 'required|min:4|max:11',
    'password' => 'required|min:3|max:16'
]);

try {
    if (Auth::attempt(['id' => $request->id, 'password' => $request->password])) {
        return to_route('dashboard');
    } else {
        return to_route('login')->with('error', 'Oppss!! Username and password is wrong');
    }
} catch (\Exception $e) {
    dd($e);
}

尝试2:手动查询并验证后调用Auth::attempt

先查询数据库将binary字段转换为字符串,确认输入值与转换后的值匹配,但传入数据库原始binary值调用Auth::attempt仍失败:

$request->validate([
    'id' => 'required|min:4|max:11',
    'password' => 'required|min:3|max:16'
]);

// 从tbl_rfaccount获取数据
$result = DB::selectOne('SELECT id, password FROM dbo.tbl_rfaccount WHERE id = CONVERT(varchar, ?)', [$request->id]);

// 将binary结果转为字符串
$idString = str_replace("\x00", "", trim($result->id));
$passString = str_replace("\x00", "", trim($result->password));

try {
    // 验证输入值与转换后的值匹配
    if ($request->id == $idString && $request->password == $passString) {
        
        // 使用数据库原始binary值调用Auth::attempt
        if (Auth::attempt(['id' => $result->id, 'password' => $result->password])) {
            return to_route('dashboard');
        } else {
            return to_route('login')->with('error', 'Login failed, please try again');
        }
    } else {
        return to_route('login')->with('error', 'Oppss!! Username and password is wrong');
    }
} catch (\Exception $e) {
    dd($e);
}

Debug结果

通过dd()输出发现,数据库中的binary(13)字段是UTF-16LE编码的字符串,不足13字节时用\x00填充:

array:6 [▼ // app\Http\Controllers\Auth\LoginController.php:62
  0 => "test6"
  1 => "t\x00e\x00s\x00t\x006\x00\x00\x00\x00"
  2 => "test6"
  3 => "123"
  4 => "1\x002\x003\x00\x00\x00\x00\x00\x00\x00\x00"
  5 => "123"
]

解决方案

由于数据库中存储的是明文的UTF-16LE编码binary值,而非Laravel默认的哈希密码,因此需要手动处理字符串与binary的转换,并绕开Auth::attempt的默认密码验证逻辑:

步骤1:创建字符串转binary(13)的辅助函数

/**
 * 将字符串转换为符合MSSQL binary(13)要求的格式
 * @param string $value 输入的字符串
 * @return string 转换后的binary字符串
 */
function stringToBinary13(string $value): string
{
    // 将UTF-8字符串转换为UTF-16LE编码
    $utf16le = mb_convert_encoding($value, 'UTF-16LE', 'UTF-8');
    // 填充\x00到13字节长度
    return str_pad($utf16le, 13, "\x00");
}

步骤2:手动完成认证与登录

在登录控制器中,将用户输入转换为对应binary格式后查询数据库,验证通过后直接调用Auth::login完成登录:

$request->validate([
    'id' => 'required|min:4|max:11',
    'password' => 'required|min:3|max:16'
]);

// 转换输入值为binary(13)格式
$binaryId = stringToBinary13($request->id);
$binaryPassword = stringToBinary13($request->password);

// 查询匹配的用户
$user = \App\Models\User::where('id', $binaryId)->first();

// 验证密码并登录
if ($user && $user->password === $binaryPassword) {
    Auth::login($user);
    return to_route('dashboard');
}

return to_route('login')->with('error', '用户名或密码错误');

补充:为用户模型添加字段转换(可选)

如果需要在其他场景中方便地使用字符串格式的id和password,可以在User模型中添加访问器,自动将binary字段转换为字符串:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    protected $table = 'tbl_rfaccount';
    protected $primaryKey = 'id';
    public $timestamps = false;

    // 将binary id转换为字符串
    public function getIdAttribute($value)
    {
        return str_replace("\x00", "", trim(mb_convert_encoding($value, 'UTF-8', 'UTF-16LE')));
    }

    // 将binary password转换为字符串
    public function getPasswordAttribute($value)
    {
        return str_replace("\x00", "", trim(mb_convert_encoding($value, 'UTF-8', 'UTF-16LE')));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:59:55