VS Code+.Netでアプリを作る(No.11):MariaDBに接続するコンソールアプリ作成時にusing method 'mysql_native_password' failedで失敗

これを参考にコンソールアプリでMySQLへ接続する。

一通り、mysqlへの接続環境は整えておく。
外部接続を許可する。
cat > /etc/mysql/conf.d/mysql.cnf << EOF
[mysqld]
bind-address = 0.0.0.0
ignore-db-dir = lost+found
EOF

ユーザー作成と、ユーザーからの内部、外部接続を許可しておく。
$ sudo mysql -u root -e 'CREATE DATABASE IF NOT EXISTS `homestead` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_bin;'
$ sudo mysql -u root -e "CREATE USER IF NOT EXISTS devadmin@'localhost' IDENTIFIED BY 'Papy-1326';"
$ sudo mysql -u root -e "CREATE USER IF NOT EXISTS devadmin@'192.168.%' IDENTIFIED BY 'Papy-1326';"
$ sudo mysql -u root -e "GRANT ALL PRIVILEGES ON homestead.* TO devadmin@'localhost';"
$ sudo mysql -u root -e "GRANT ALL PRIVILEGES ON homestead.* TO devadmin@'192.168.%';"
$ sudo mysql -u root -e "GRANT ALL PRIVILEGES ON mysql.* TO devadmin@'192.168.%';"

プロジェクトを生成し、MySQLのパッケージをインストールする。
$ dotnet new console –o mysqlefcore
$ cd mysqlefcore
$ dotnet add package MySql.Data.EntityFrameworkCore --version 8.0.20
$ dotnet restore (依存関係の復元→dotnet build or run時に実行されるのでしなくてもよい)

root直下にLibraryModel.csファイルを作成。 Book, Publisherモデルを定義している。
using System.Collections.Generic;

namespace mysqlefcore
{
  public class Book
  {
    public string ISBN { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string Language { get; set; }   
    public int Pages { get; set; }
    public virtual Publisher Publisher { get; set; }
  }

  public class Publisher
  {
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }
  }
}

root直下にLibraryContext.csファイルを作成。 Entity Frameworkを使用してデータにアクセスするデータアクセス層として、DBContextの継承クラスを定義する。
using Microsoft.EntityFrameworkCore;
// using MySQL.Data.EntityFrameworkCore.Extensions;
// =>使わないし、エラーを吐くのでコメントする。

namespace mysqlefcore
{
  public class LibraryContext : DbContext
  {
    public DbSet<Book> Book { get; set; }
    
    public DbSet<Publisher> Publisher { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseMySQL("server=localhost;database=library;user=user;password=password");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      base.OnModelCreating(modelBuilder);

      modelBuilder.Entity<Publisher>(entity =>
      {
        entity.HasKey(e => e.ID);
        entity.Property(e => e.Name).IsRequired();
      });

      modelBuilder.Entity<Book>(entity =>
      {
        entity.HasKey(e => e.ISBN);
        entity.Property(e => e.Title).IsRequired();
        entity.HasOne(d => d.Publisher)
          .WithMany(p => p.Books);
      });
    }
  }
}

最後にProgram.csを書き換える。
using Microsoft.EntityFrameworkCore;
using System;
using System.Text;

namespace mysqlefcore
{
  class Program
  {
    static void Main(string[] args)
    {
      InsertData();
      PrintData();
    }

    private static void InsertData()
    {
      using(var context = new LibraryContext())
      {
        // Creates the database if not exists
        context.Database.EnsureCreated();

        // Adds a publisher
        var publisher = new Publisher
        {
          Name = "Mariner Books"
        };
        context.Publisher.Add(publisher);

        // Adds some books
        context.Book.Add(new Book
        {
          ISBN = "978-0544003415",
          Title = "The Lord of the Rings",
          Author = "J.R.R. Tolkien",
          Language = "English",
          Pages = 1216,
          Publisher = publisher
        });
        context.Book.Add(new Book
        {
          ISBN = "978-0547247762",
          Title = "The Sealed Letter",
          Author = "Emma Donoghue",
          Language = "English",
          Pages = 416,
          Publisher = publisher
        });

        // Saves changes
        context.SaveChanges();
      }
    }

    private static void PrintData()
    {
      // Gets and prints all books in database
      using (var context = new LibraryContext())
      {
        var books = context.Book
          .Include(p => p.Publisher);
        foreach(var book in books)
        {
          var data = new StringBuilder();
          data.AppendLine($"ISBN: {book.ISBN}");
          data.AppendLine($"Title: {book.Title}");
          data.AppendLine($"Publisher: {book.Publisher.Name}");
          Console.WriteLine(data.ToString());
        }
      }
    }
  }
}
これで $dotnet run する。
すると、最初のcontext.Database.EnsureCreated();で以下のエラーが発生する。
mysqlefcore Error: 0 : Authentication to host 'localhost' for user 'user' using method 'mysql_native_password' failed with message: Access denied for user 'user'@'localhost' (using password: YES)
ココによると、MySQL8からデフォルトの認証方式がmysql_native_passwordから*ハッシュ化方式caching_sha2_passwordへ変更されたことによるエラーとのこと。
$ mysql --version
 mysql  Ver 15.1 Distrib 10.4.13-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
$ MariaDB [(none)]> SELECT * FROM mysql.global_priv;
| localhost | devadmin         | {"access":0,"plugin":"mysql_native_password","authentication_string":"*D9547C26931028C1F3D0DEF9A477812598E3C06A","password_last_changed":1590238998}
| 192.168.% | devadmin         | {"access":0,"plugin":"mysql_native_password","authentication_string":"*D9547C26931028C1F3D0DEF9A477812598E3C06A","password_last_changed":1590239017}
Vagrantのhomesteadは、MariaDB10.4でありdefaultは、mysql_native_password。 ハッシュ化方式caching_sha2_passwordはサポートされていないためNG。。
VagrantでUbuntu20.04LTS環境を作ってMySQL8を入れ直した方が早そう。

参考:


コメント

このブログの人気の投稿

ソリューション構成ごとにconfigファイルを作成する

C++の古いプロジェクトのビルドでerror MIDL2311 : statements outside library block are illegal in mktyplib compatability mode

web.config debug/releaseの内容を変換構文を使って切り替える