截至 Dotnet Core 2.0 尚未移轉 System.DirectoryServices
,因此以前寫的 LDAP 驗證程式碼無法移轉到 Dotnet Core 中使用,在官方尚未提供對應的解法時,可以使用 Novell.Directory.Ldap.NETStandard
第三方套件來處理。
LDAP 對很多公司來說是非常常用的驗證技術,大家可以到這個 #2089 issues 加一,讓微軟知道您的想法。
更新!System.DirectoryServices 已經支援 Dotnet Core 囉!使用前請先確認您的目標框架是符合 .NET Standard 2.0 的 Dotnet 框架。
LDAP 的簡介請參考這篇。
測試環境
如果手邊沒有可以測試的 LDAP 伺服器,可以利用 forumsys 提供的測試環境,相關資訊如下:
- 所提供的 LDAP 資料都是唯讀的
- 伺服器連線資訊
- Server:
ldap.forumsys.com
- Port:
389
- Server:
- 管理者資訊
- Bind DN:
cn=read-only-admin,dc=example,dc=com
- Bind Password:
password
- Bind DN:
- 帳戶資訊
- 所有帳戶的密碼都是
password
- 使用
uid
來識別帳戶 - 使用
ou
來歸類群組
- 所有帳戶的密碼都是
- 帳戶群組一
- Group CN:
ou=mathematicians,dc=example,dc=com
- UID:
- riemann
- gauss
- euler
- euclid
- Group CN:
- 帳戶群組二
- Group CN:
ou=scientists,dc=example,dc=com
- UID:
- einstein
- newton
- galieleo
- tesla
- Group CN:
IDMWORKS/DirEx 這個開源專案提供線上查看 LDAP 目錄的功能,點此可查看上列 forumsys 的目錄內容。
實作驗證
使用 Novell.Directory.Ldap.NETStandard 第三方套件來實現 LDAP 驗證還滿簡單的,下面我們用 Dotnet CLI 和 VS Code 來實作看看。
Dotnet CLI 命令請參考.NET Core 命令列介面工具的官方文件
透過 dotnet new --list
可以列出目前的範本清單,這裡使用主控台應用程式 console
,執行下列指令建立專案:
dotnet new console -n DemoNovellLdapAuth
接著使用 VS Code 開啟專案目錄,並開啟內建的終端機功能,執行下列指令加入 Novell.Directory.Ldap.NETStandard 套件,接著執行 dotnet restore
還原套件。
dotnet add package Novell.Directory.Ldap.NETStandard
修改 Main
主程式:
static void Main(string[] args)
{
var User = new { username = "tesla", password = "password" };
var result = SimpleLdapAuth(User.username, User.password);
Console.WriteLine($"LDAP Auth Result: {result}");
}
並建立 SimpleLdapAuth
方法:
public static bool SimpleLdapAuth(string username, string password)
{
var Host = "ldap.forumsys.com";
var BindDN = "cn=read-only-admin,dc=example,dc=com";
var BindPassword = "password";
var BaseDC = "dc=example,dc=com";
try
{
using (var connection = new LdapConnection())
{
connection.Connect(Host, LdapConnection.DEFAULT_PORT);
connection.Bind(BindDN, BindPassword);
var searchFilter = $"(uid={username})";
var entities = connection.Search(BaseDC, LdapConnection.SCOPE_SUB, searchFilter, null, false);
string userDn = null;
while (entities.hasMore())
{
var entity = entities.next();
var account = entity.getAttribute("uid");
if (account != null && account.StringValue == username)
{
userDn = entity.DN;
break;
}
}
if (string.IsNullOrWhiteSpace(userDn)) return false;
connection.Bind(userDn, password);
return connection.Bound;
}
}
catch (LdapException e)
{
throw e;
}
}
執行 dotnet run
運行此應用程式。
程式碼少少的,也滿簡單的,大致提一下關鍵方法:
connection.Connect(string host, int port)
- 建立連線
- Port 可直接使用
LdapConnection.DEFAULT_PORT
,即為 389 埠
connection.Bind(string dn, string password)
- 主要藉此連結管理者帳號,再進行查詢的動作
- 順便一提,
connection.Bound
會回傳布林值,作為判斷是否連結成功
connection.Search(string base, int scope, string filter, string[] attrs, bool typesOnly)
- base 為要開始查詢的 DN 位置
- scope 搜尋的範圍
SCOPE_BASE
只查詢目前 DN 的項目SCOPE_ONE
只查詢目前 DN 及下層 DN 的項目SCOPE_SUB
查詢目前 DN 下的樹(通常會使用此設定)
- filter 過濾條件,查詢語法請參考這篇
- attrs 要取回的屬性清單,可設定成
null
將所有屬性取回 - typesOnly
true
只返回名稱,false
返回名稱及屬性
上面的方法需要一個管理者帳號做發動,如果你可以確定你的 LDAP 目錄結構,並且寫出鎖定某位使用者帳號的查詢語法,帳號驗證的程式碼可以精簡成如下:
public static bool SelfLdapAuth(string username, string password)
{
var Host = "ldap.forumsys.com";
var BaseDC = "dc=example,dc=com";
try
{
using (var connection = new LdapConnection())
{
connection.Connect(Host, LdapConnection.DEFAULT_PORT);
connection.Bind($"uid={username},{BaseDC}", password);
return connection.Bound;
}
}
catch (LdapException e)
{
throw e;
}
}
重點只要擺在 connection.Bind(string dn, string password)
中 dn
的設定即可。
本篇完整範例程式碼請參考 poychang/DemoDotnetCoreNovellLdap。
參考資料: