Laravel - 不允许从数据类型 nvarchar 到 varbinary 隐式转换

问题描述 投票:0回答:1

我正在使用 Laravel 8.40 并尝试将我的 WebApp 迁移到

SQL Server 2008 R2 SP1

在 MySQL 上一切正常,但在我迁移数据库(使用普通 SQL 命令)后,在 IIS 7.5、PHP 7.4、MS SQL Server 2008 上尝试我的应用程序时,我在尝试注册用户时收到此错误

SQLSTATE[42000]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Implicit conversion from data type nvarchar to varbinary is not allowed. Use the CONVERT function to run this query. (SQL: insert into [users] ([username], [email], [password]) values (wolf, [email protected], $2y$10$1b.fjIEbBXgB30J8E6QIsuroXwXqx.WezBIodnnqOgszUJ92LvGgO))

我的用户模型(User.php)看起来像这样

<?php
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
use App\Casts\uuid;
use Illuminate\Support\Facades\DB;
/**
 * @OA\Schema(
 *     title="User",
 *     description="User model",
 *     @OA\Xml(
 *         name="User"
 *     )
 * )
 */
class User extends Authenticatable
{
    use Notifiable;

    protected $primaryKey = 'UUID';

    public $incrementing = false;
    public $timestamps = false;

    protected $casts = [
        'UUID' => uuid::class,
        'password' => 'string',
        'created_at' => 'timestamp',
        'updated_at' => 'timestamp'
    ];

    protected $dates = [
        'created_at',
        'updated_at'
    ];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'username', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * @OA\Property(
     *      title="username",
     *      description="username",
     *      example="veso266"
     * )
     *
     * @var string
     */
    public $UUID;

    /**
     * @OA\Property(
     *      title="username",
     *      description="username",
     *      example="wolf"
     * )
     *
     * @var string
     */
    public $username;

    /**
     * @OA\Property(
     *      title="email",
     *      description="E-Mail Address",
     *      example="[email protected]"
     * )
     *
     * @var string
     */
    public $email;

    /**
     * @OA\Property(
     *      title="email",
     *      description="E-Mail Verificytion date",
     *      example="null"
     * )
     *
     * @var timestamp
     */
    public $email_verified_at;

    /**
     * @OA\Property(
     *      title="password",
     *      description="User Password",
     *      example="$2y$10$HPfubOU.XX/OptS3sAH73OC3iz6BLsJvIKFyFaoLMt3.."
     * )
     *
     * @var string
     */
    public $password;

    /**
     * @OA\Property(
     *      title="remember_tokem",
     *      description="If we shall remember the user token",
     *      example="null"
     * )
     *
     * @var string
     */
    public $remember_token;

    /**
     * @OA\Property(
     *      title="created_at",
     *      description="User Creation Date",
     *      example="1621804555"
     * )
     *
     * @var timestamp
     */
    public $created_at;
    /**
     * @OA\Property(
     *      title="updated_at",
     *      description="User Update Date",
     *      example="1621804600"
     * )
     *
     * @var timestamp
     */
    public $updated_at;

    public function generateToken()
    {
        $this->api_token = Str::random(60);
        $this->save();

        return $this->api_token;
    }

    public static function status()
    {
        $sql = DB::select("SELECT 
                              users.UUID, 
                              users.username, 
                              users.email, 
                              users.api_token
                           FROM users;");

        return $sql;
    }
}

我的演员\uuid.php

<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class uuid implements CastsAttributes
{
    /**
     * Cast the given value.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return mixed
     */
    public function get($model, $key, $value, $attributes)
    {
        $hex = bin2hex($value);
        return substr($hex, 0,8) .'-'. substr($hex, 8,4) .'-'. substr($hex, 12,4) .'-'. substr($hex, 16,4) .'-'. substr($hex, 20,12);
    }

    /**
     * Prepare the given value for storage.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return mixed
     */
    public function set($model, $key, $value, $attributes)
    {
        return hex2bin($value);
    }
}

我的RegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use MyLibs\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'username' => ['required', 'string', 'max:255', 'unique:users', 'regex:/^\S*$/u'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\User
     */
    protected function create(array $data)
    {
        return User::create([
            'username' => $data['username'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }

    public function register(Request $request)
    {
        // Here the request is validated. The validator method is located
        // inside the RegisterController, and makes sure the name, email
        // password and password_confirmation fields are required.
        $this->validator($request->all())->validate();

        // A Registered event is created and will trigger any relevant
        // observers, such as sending a confirmation email or any
        // code that needs to be run as soon as the user is created.
        event(new Registered($user = $this->create($request->all())));

        // After the user is created, he's logged in.
        $this->guard()->login($user);

        // And finally this is the hook that we want. If there is no
        // registered() method or it returns null, redirect him to
        // some other URL. In our case, we just need to implement
        // that method to return the correct response.
        return $this->registered($request, $user)
            ?: redirect($this->redirectPath());
    }

    protected function registered(Request $request, $user)
    {
        $user->generateToken();

        return response()->json(['data' => $user->toArray()], 201);
    }
}

这是我在数据库中为用户提供的表格

IF OBJECT_ID('dbo.users', 'U') IS NOT NULL
    DROP TABLE dbo.users;
GO

-- Create the `users` table
CREATE TABLE dbo.users (
    UUID UNIQUEIDENTIFIER NOT NULL,
    username NVARCHAR(10) NOT NULL,
    email NVARCHAR(255) NOT NULL,
    email_verified_at DATETIME NULL,
    password VARBINARY(60) NOT NULL, -- SHA512 Hash stored as binary
    api_token NVARCHAR(60) NULL,
    remember_token NVARCHAR(100) NULL,
    created_at DATETIME NULL DEFAULT ('0001-01-01T00:00:00'),
    updated_at DATETIME NULL DEFAULT ('0001-01-01T00:00:00'),
    CONSTRAINT PK_users PRIMARY KEY (UUID),
    CONSTRAINT UQ_users_email UNIQUE (email),
    CONSTRAINT UQ_users_api_token UNIQUE (api_token)
);
GO

-- Triggers for the `users` table
-- Trigger to generate UUID on insert
CREATE TRIGGER trg_generate_UUID
ON dbo.users
INSTEAD OF INSERT
AS
BEGIN
    DECLARE @newUUID UNIQUEIDENTIFIER
    SET @newUUID = NEWID() -- Generates a unique UUID
    INSERT INTO dbo.users (UUID, username, email, email_verified_at, password, api_token, remember_token, created_at, updated_at)
    SELECT @newUUID, username, email, email_verified_at, password, api_token, remember_token, COALESCE(created_at, GETDATE()), COALESCE(updated_at, GETDATE())
    FROM inserted;
END;
GO

-- Trigger to set created_at and updated_at on insert
CREATE TRIGGER trg_user_create
ON dbo.users
AFTER INSERT
AS
BEGIN
    UPDATE dbo.users
    SET created_at = GETDATE(),
        updated_at = GETDATE()
    WHERE UUID IN (SELECT UUID FROM inserted);
END;
GO

-- Trigger to set updated_at on update
CREATE TRIGGER trg_user_update
ON dbo.users
AFTER UPDATE
AS
BEGIN
    UPDATE dbo.users
    SET updated_at = GETDATE()
    WHERE UUID IN (SELECT UUID FROM inserted);
END;
GO

所有其他答案都是这样的: 不允许从数据类型 varchar(max) 到 varbinary(max) 的隐式转换。使用 CONVERT 函数运行此查询

正在使用原始 SQL 语句,而我没有(我使用 ORM),所以甚至不确定在哪里放置 CONVERT 语句?

我能做什么?

php laravel sql-server-2008-r2 iis-7.5
1个回答
0
投票

Hash::make()
返回的哈希密码是一个字符串,而不是二进制。这里的修复是更新表架构,以便密码字段也是
NVARCHAR
而不是
VARBINARY

哈希密码以与算法、盐和其他参数兼容的字符串形式返回,看起来像 crypt()

因此,您希望将密码存储为字符串而不是二进制。
    

© www.soinside.com 2019 - 2024. All rights reserved.