具有特殊安全需求的高階使用者可以為 MySQL Connector/NET 應用程式建立自己的身份驗證外掛程式。您可以擴展交握協定,新增自訂邏輯。如需 MySQL 身份驗證外掛程式的背景和使用資訊,請參閱 身份驗證外掛程式 和 編寫身份驗證外掛程式。
若要編寫自訂身份驗證外掛程式,您需要參考組件 MySql.Data.dll
。編寫身份驗證外掛程式相關的類別位於命名空間 MySql.Data.MySqlClient.Authentication
。
自訂身份驗證外掛程式的運作方式
在交握期間的某個時間點,會呼叫內部方法
void Authenticate(bool reset)
MySqlAuthenticationPlugin
。此方法會依序呼叫目前外掛程式的數個可覆寫方法。
建立身份驗證外掛程式類別
您將身份驗證外掛程式邏輯放入衍生自 MySql.Data.MySqlClient.Authentication.MySqlAuthenticationPlugin
的新類別中。下列方法可用於覆寫
protected virtual void CheckConstraints()
protected virtual void AuthenticationFailed(Exception ex)
protected virtual void AuthenticationSuccessful()
protected virtual byte[] MoreData(byte[] data)
protected virtual void AuthenticationChange()
public abstract string PluginName { get; }
public virtual string GetUsername()
public virtual object GetPassword()
protected byte[] AuthData;
以下是每個方法的簡要說明
/// <summary>
/// This method must check authentication method specific constraints in the
environment and throw an Exception
/// if the conditions are not met. The default implementation does nothing.
/// </summary>
protected virtual void CheckConstraints()
/// <summary>
/// This method, called when the authentication failed, provides a chance to
plugins to manage the error
/// the way they consider decide (either showing a message, logging it, etc.).
/// The default implementation wraps the original exception in a MySqlException
with an standard message and rethrows it.
/// </summary>
/// <param name="ex">The exception with extra information on the error.</param>
protected virtual void AuthenticationFailed(Exception ex)
/// <summary>
/// This method is invoked when the authentication phase was successful accepted
by the server.
/// Derived classes must override this if they want to be notified of such
condition.
/// </summary>
/// <remarks>The default implementation does nothing.</remarks>
protected virtual void AuthenticationSuccessful()
/// <summary>
/// This method provides a chance for the plugin to send more data when the
server requests so during the
/// authentication phase. This method will be called at least once, and more
than one depending upon whether the
/// server response packets have the 0x01 prefix.
/// </summary>
/// <param name="data">The response data from the server, during the
authentication phase the first time is called is null, in
subsequent calls contains the server response.</param>
/// <returns>The data generated by the plugin for server consumption.</returns>
/// <remarks>The default implementation always returns null.</remarks>
protected virtual byte[] MoreData(byte[] data)
/// <summary>
/// The plugin name.
/// </summary>
public abstract string PluginName { get; }
/// <summary>
/// Gets the user name to send to the server in the authentication phase.
/// </summary>
/// <returns>An string with the user name</returns>
/// <remarks>Default implementation returns the UserId passed from the
connection string.</remarks>
public virtual string GetUsername()
/// <summary>
/// Gets the password to send to the server in the authentication phase. This
can be a string or a
/// </summary>
/// <returns>An object, can be byte[], string or null, with the password.
</returns>
/// <remarks>Default implementation returns null.</remarks>
public virtual object GetPassword()
/// <summary>
/// The authentication data passed when creating the plugin.
/// For example in mysql_native_password this is the seed to encrypt the
password.
/// </summary>
protected byte[] AuthData;
身份驗證外掛程式範例
此範例示範如何建立身份驗證外掛程式,然後透過組態檔啟用它。
建立主控台應用程式,並新增對
MySql.Data.dll
的參考。將主要 C# 程式設計為如下所示
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MySql.Data.MySqlClient; namespace AuthPluginTest { class Program { static void Main(string[] args) { // Customize the connection string as necessary. MySqlConnection con = new MySqlConnection("server=localhost; database=test; user id=myuser; password=mypass"); con.Open(); con.Close(); } } }
建立外掛程式類別。在此範例中,我們透過使用原始外掛程式中的相同程式碼來新增 Native password 外掛程式的 「替代」實作。
注意從 MySQL 伺服器 8.4.0 開始,mysql_native_password 外掛程式預設為停用,並從 MySQL 伺服器 9.0.0 開始移除。
我們將類別命名為
MySqlNativePasswordPlugin2
using System.IO; using System; using System.Text; using System.Security.Cryptography; using MySql.Data.MySqlClient.Authentication; using System.Diagnostics; namespace AuthPluginTest { public class MySqlNativePasswordPlugin2 : MySqlAuthenticationPlugin { public override string PluginName { get { return "mysql_native_password"; } } public override object GetPassword() { Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword"); return Get411Password(Settings.Password, AuthData); } /// <summary> /// Returns a byte array containing the proper encryption of the /// given password/seed according to the new 4.1.1 authentication scheme. /// </summary> /// <param name="password"></param> /// <param name="seed"></param> /// <returns></returns> private byte[] Get411Password(string password, byte[] seedBytes) { // if we have no password, then we just return 1 zero byte if (password.Length == 0) return new byte[1]; SHA1 sha = new SHA1CryptoServiceProvider(); byte[] firstHash = sha.ComputeHash(Encoding.Default.GetBytes(password)); byte[] secondHash = sha.ComputeHash(firstHash); byte[] input = new byte[seedBytes.Length + secondHash.Length]; Array.Copy(seedBytes, 0, input, 0, seedBytes.Length); Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length); byte[] thirdHash = sha.ComputeHash(input); byte[] finalHash = new byte[thirdHash.Length + 1]; finalHash[0] = 0x14; Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length); for (int i = 1; i < finalHash.Length; i++) finalHash[i] = (byte)(finalHash[i] ^ firstHash[i - 1]); return finalHash; } } }
請注意,外掛程式實作僅覆寫
GetPassword
,並提供使用 4.1 協定加密密碼的實作。在GetPassword
主體中新增下列行,以確認已有效使用外掛程式。Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword");
提示您也可以在該方法上設定中斷點。
在組態檔中啟用新的外掛程式
<?xml version="1.0"?> <configuration> <configSections> <section name="MySQL" type="MySql.Data.MySqlClient.MySqlConfiguration, MySql.Data"/> </configSections> <MySQL> <AuthenticationPlugins> <add name="mysql_native_password" type="AuthPluginTest.MySqlNativePasswordPlugin2, AuthPluginTest"></add> </AuthenticationPlugins> </MySQL> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup></configuration>
執行應用程式。在 Visual Studio 中,您會在偵錯視窗中看到訊息
Calling MySqlNativePasswordPlugin2.GetPassword
。
繼續增強身份驗證邏輯,如果需要,可以覆寫更多方法。