SQL Server安全(7/11):使用跨資料庫所有權鏈接(Cross-Database Ownership Chaining)的跨資料庫安全

来源:http://www.cnblogs.com/woodytu/archive/2016/03/31/5330444.html
-Advertisement-
Play Games

在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。 從讓人眼花繚亂的 ...


在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。


從讓人眼花繚亂的客戶端使用連接,通過到處分佈的網路,尤其是互聯網,關係資料庫在各種應用程式里廣泛使用。這使數據對任何人,在任何地方都可訪問。資料庫可以保存人類知識的很大部分,包括高度敏感的個人信息和讓國際商務工作的關鍵數據。

對於想要偷取數據或通過篡改數據來傷害數據的擁有者的 人來說,這些功能使資料庫成為有吸引力的目標。確保你的數據安全是SQL Server配置和使用它來保存數據的程式的重要部分。這個系列會探尋SQL Server 2012安全的基本,這樣的話你可以保護你的數據和伺服器資源,按你需要的安全等級來保護數據,免受這些威脅對你數據的影響。大部分信息對SQL Server的早期版本也適用,回到SQL Server 2005也可以,因為那是微軟在產品里徹底檢查安全的時候。但我也會談論只在SQL Server 2012和後續版本里才有的功能。

大部分時間,你只要關註只有一個所有者的,在一個獨立資料庫里的數據和對象訪問安全。但有時候你需要接觸到外面的資料庫從多個資料庫範文數據和對象,它引起一些安全問題,增加了數據訪問的複雜性。在這篇文章里,你會學習跨資料庫所有權鏈接,這樣的話,你可以接觸到跨資料庫邊界的安全。

所有權鏈接

大部分時間,你都很可能創建引用其它對象的資料庫,所有對象都包含在同個資料庫里。例子包括,在同個資料庫里訪問表的存儲過程,在同個資料庫里把錶鏈接一起的視圖等等。但是有時候,你會需要創建越過資料庫邊界的訪問其它對象的對象。對於大部分,對於跨資料庫範文的安全規則都是一致的,只要在同個資料庫里。訪問的用戶需要在它們直接訪問的對象上有必要的許可,連續的所有權鏈接允許SQL Server縮短許可檢查等等。畢竟,SQL Server不能放鬆警惕,不管對象放在哪裡!在一個資料庫里,所有權鏈接簡化安全管理,同樣也適用於跨資料庫。

你是否在一個資料庫里還是跨過資料庫邊界,所有權鏈接如何工作的基本都是一樣的。所有的資料庫對象有個擁有者,所有者控制在它所有的對象上誰有許可。訪問其它對象的對象——例如在SELECT語句里連接多個表的存儲過程——構成一個所有權鏈接,它是連續的,只要單個所有者擁有所有涉及的對象。

在最高層對象上擁有許可的用戶的結果——一個存儲過程或視圖,例如——訪問其它對象的用戶不需要在潛在對象上有許可,只要這是一個連續的所有權鏈接。SQL Server在這樣的對象上,一旦驗證在最高層對象擁有許可,就停止檢查許可。這個架構給所有者在潛在對象的訪問,更多更好的控制,因為用戶只需要在它們直接訪問的對象上有許可。

提示:

理解所有權鏈接只適用於對象許可非常重要,例如SELECT,UPDATE和EXECUTE的操作。SQL Server總在數據定義語句上檢查許可,因為這些許可只適用於語句而不是對象。

跨資料庫所有權鏈接

跨資料庫所有權鏈接是所有權鏈接的延伸,所有的對象——包括用戶直接訪問的對象和潛在引用的對象——都在一個資料庫里。跨資料庫所有權鏈接的唯一區別是跨資料庫邊界。因此你可以在一個資料庫里有個在多個資料庫里把數據連接一起的視圖。或在多個資料庫里訪問對象的存儲過程。在這些情況下,用戶直接訪問的源對象取決於在另一個資料庫里包含的對象。

所有權鏈接的兩種類型直接的唯一重要區別是訪問資料庫,對象所有者的主體。資料庫用戶是在單個資料庫里完全包含的主體。即使多個資料庫每個有同樣的名稱,它們是獨立的,不同的主體,因此不能在連續的所有權鏈接里參與,除非所有這些用戶映射到同個資料庫級別的登錄。因此它是相關所有者的登錄,不是資料庫用戶。那就是關鍵概念:在連續所有權鏈接里對象的公共所有者是伺服器級別的主體,而不是資料庫級別的主體。

在內部,SQL Server通過它們的安全ID(SID)而不是用戶名來標識對象所有者。在單個資料庫里,單個用戶擁有的所有對象有一個SID ,作為所有者,因為在資料庫里只有一個用戶有那個名稱。但跨數據,SID是在伺服器級別上的終極登錄。在不同的資料庫里不同的用戶可以關聯不同登錄,因此會有不同的SID。這是用戶和登錄相比,很可能是一個最容易混淆的方面,因此這點你要確定清楚。

連續的跨資料庫所有權鏈接需要對象所有者的全部——源對象和所有引用的對象——用同樣的SID映射到同個登錄。

探尋跨資料庫所有權鏈接

這篇文章的代碼演示瞭如何使用跨資料庫所有權鏈接,並探尋它的特點。代碼通過在伺服器級別創建名為SharedLogin的登錄開始,如代碼7.1所示。接下來代碼使用這個作為用於在所有權鏈接里對象的共用所有者。

1 USE master;
2 GO
3 
4 IF SUSER_SID('SharedLogin') IS NOT NULL DROP LOGIN SharedLogin;
5 CREATE LOGIN SharedLogin WITH password = 'Y&2!@37z#F!l1zB';
6 GO

代碼7.1:創建會是對象所有者的SharedLogin登錄的代碼

在跨資料庫所有權鏈接里我們要涉及到兩個資料庫,因此接下來的代碼會創建它們。包含用戶直接訪問對象的資料庫名為SourceDB,引用對象的資料庫會是ChainedDBChainedDB包含一個dbo.AlaskaCity表,包含阿拉斯加三個最大城市的人口的一些數據。代碼7.2創建ChainedDB和它的AlaskaCity表,在表裡插入一些數據,用2010的人口調查數據。

 1 IF DB_ID('ChainedDB') IS NOT NULL DROP DATABASE ChainedDB;
 2 CREATE DATABASE ChainedDB;
 3 GO
 4 USE ChainedDB;
 5 GO
 6 
 7 -- Create a table for access from another database
 8 CREATE TABLE dbo.AlaskaCity
 9 (
10     AlaskaCityID INT NOT NULL IDENTITY(1, 1), 
11     CityName NVARCHAR(20) NOT NULL, 
12     Population INT NOT NULL
13     CONSTRAINT PK_AlaskaCity PRIMARY KEY (AlaskaCityID)
14 );
15 GO
16 
17 INSERT INTO dbo.AlaskaCity (CityName, Population)
18     VALUES ('Fairbanks', 31535), ('Anchorage', 291826), ('Juneau', 31275);
19 GO

代碼7.2:創建ChainedDB資料庫和有插入樣本數據的AlaskaCity表的代碼

接下來的代碼創建SourceDB資料庫,包含一個用戶在ChainedDB資料庫里,從AlaskaCity直接訪問,獲取數據的視圖。如代碼7.3所示,包含一個SELECT語句來測試一切正常。如果你以sysadmin登錄的話,這一切都會正常,因為在SQL Server實例里你有所有對象的完整訪問,有用所有創建的對象,目前是dbo,你應該可以看到阿拉斯加的人口數據。以sysadmin運行是很方便,但對生產使用並不安全,通常用戶訪問代碼不會有所有對象的成員資格。

 1 IF DB_ID('SourceDB') IS NOT NULL DROP DATABASE SourceDB;
 2 CREATE DATABASE SourceDB;
 3 GO
 4 USE SourceDB;
 5 GO
 6 
 7 -- Create a view that accesses ChainedDB.dbo.AlaskaCity
 8 CREATE VIEW dbo.AlaskaCitiesView AS
 9     SELECT * FROM ChainedDB.dbo.AlaskaCity;
10 GO
11 
12 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;

代碼7.3:創建SourceDB資料庫和在ChainedDB資料庫里訪問AlaskaCity表的視圖的代碼

現在我們有2個資料庫,一個是在另一個資料庫里,有引用另一個對象,以sysadmin運行一切正常。因此現在我們創建一個更實際的例子來打破代碼。代碼7.4在SourceDB資料庫里創建一個映射到SharedLoginSourceUser,併在AlaskaCitiesView視圖上授予SELECT許可給用戶。然後代碼修改執行上下文到SharedLogin,嘗試訪問視圖。SELECT語句會成功麽?

 1 USE SourceDB;
 2 GO
 3 
 4 -- Create a user in the SourceDB who will access the view
 5 CREATE USER SourceUser FOR LOGIN SharedLogin;
 6 GRANT SELECT ON dbo.AlaskaCitiesView TO SourceUser;
 7 GO
 8 
 9 -- Try accessing the view as SourceUser
10 EXECUTE AS LOGIN = 'SharedLogin';
11 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;
12 GO
13 REVERT;

代碼7.4:創建SourceUser資料庫用戶,映射到SharedLogin,並用代碼測試訪問視圖

沒有成功,SELECT語句拋出了一個異常。

我們暫時先退一步。我們有完整的跨資料庫所有權鏈接:視圖和表享有共同成員資格,它是我的登錄(sysadmin),同時在資料庫里映射到dbo。到這裡都一切正常。但跨資料庫成員資格所有權鏈接沒有在資料庫實例里啟用,對2個新的資料庫也沒有啟用。接下來我們來啟用它。

啟用跨資料庫所有權鏈接

在SQL Server實例的全新安裝里,使用跨資料庫成員資格所有權鏈接的選項預設是關掉的。這是因為啟用這個選項,實例的安全護甲里打開了幾個小孔;在這篇文章里稍後會解釋。當這個選項禁用時,當代碼依賴於成員資格鏈接是,會生成許可拒絕的錯誤。(一會你就會看到,在讓代碼正常工作前,這不是你要修正的唯一問題,但是我們第一個要處理的)。

你可以在伺服器級別或資料庫級別啟用跨資料庫成員資格鏈接,在伺服器級別使用T-SQL語句或SSMS。

在伺服器級別啟用

對所有的資料庫,在伺服器級別啟用跨資料庫所有權鏈接選項。如果你啟用它,它是針對所有資料庫的,你不能在資料庫級別限制它。

使用SSMS,在對象瀏覽器右擊伺服器實例,從彈出的菜單選擇【屬性】。選擇【安全性】頁,在對話框的底部,你會看到【跨資料庫所有權鏈接】選項,如插圖7.1所示。點擊【確定】,在實例里的所有資料庫會啟用它。

插圖7.1:使用伺服器屬性對話框啟用跨資料庫所有權鏈接

你也可以使用T-SQL代碼做同樣的修改,如代碼7.5所示。和其它伺服器實例選項,設置cross db ownership chaining選項為1來啟用它,設回0禁止它。記得使用RECONFIGURE語句,這樣的話你不需要重啟實例讓修改生效。一旦你執行了這個代碼,你可以在這個資料庫實例里的任何資料庫里,使用跨資料庫所有權鏈接。

1 USE master;
2 GO
3 
4 EXECUTE sp_configure 'cross db ownership chaining', 1;
5 RECONFIGURE;

代碼7.5:使用sp_configure系統存儲過程啟用跨資料庫所有權鏈接

不管你用SSMS還是T-SQL代碼來啟用跨資料庫所有權鏈接,現在把它關閉。這不是啟用它的最佳方式,除非你想在實例里的每個資料庫里從源對象里引用對象。不是的話,在實例級別啟用它太不安全,這樣做不明智。

只在需要的資料庫啟用跨資料庫所有權鏈接才是明智的。

在資料庫級別啟用

如果在伺服器級別你禁用了跨資料庫所有權鏈接,如果你想使用它的話,你必須在資料庫級別啟用它。如果對於一個資料庫禁用了,資料庫一點也不能參與跨資料庫所有權鏈接,不管是源還是鏈接資料庫。為了讓鏈接能夠工作,源和鏈接資料庫的設置必須啟用。

對於所有的資料庫,當你創建或附加它們的時候,預設跨資料庫所有權鏈接是禁用的。但對master,msdb,tempdb系統資料庫是啟用的,對於model資料庫是禁用的。因為SQL Server內部使用跨資料庫所有權鏈接,對於這些系統資料庫,你不能啟用或停用它。

提示:如果你分離,重新附加已經啟用跨資料庫所有權鏈接的資料庫,在附加回資料庫後,你需要重新啟用它。對於在伺服器級別啟用的無效,因為它自動應用到所有的資料庫。

可惜SSMS在資料庫屬性對象框里有跨資料庫所有權鏈接啟用選項,如果在插圖7.2選項頁所示,它是只讀的。為了修改資料庫的這個值,你需要使用代碼7.6,對SourceDBChainedDB資料庫同時啟用。這個代碼使用ALTER DATABASE語句的SET DB_CHAINING選項來打開鏈接的開和關。

插圖7.2:對於ChainedDB資料庫,跨資料庫所有權鏈接選項是只讀的

1 ALTER DATABASE ChainedDB SET DB_CHAINING ON;
2 ALTER DATABASE SourceDB SET DB_CHAINING ON;
3 GO

代碼7.6:在兩個資料庫里,ALTER DATABASE代碼來啟用跨資料庫所有權鏈接。

在兩個資料庫里同時啟用了跨資料庫所有權鏈接,你可以再次嘗試用SharedLogin的安全上下文訪問視圖;代碼7.7再次展示這個代碼。

1 USE SourceDB;
2 GO
3 
4 EXECUTE AS LOGIN = 'SharedLogin';
5 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;
6 GO
7 REVERT;

代碼7.7:使用跨資料庫所有權鏈接訪問嫩跨資料庫邊界的對象

但代碼還是返回同樣的錯誤。這次的問題是還有另一個要求:訪問視圖對象的用戶必須要訪問鏈接資料庫。用戶在潛在的對象上不需要有許可。事實上,用戶在那個資料庫里不需要任何許可。

代碼7.8展示了你可以如何解決這個問題。代碼在ChainedDB資料庫創建了一個映射到SharedLoginChainedUser用戶。這給SharedLogin在那個資料庫里一個小立足點,這是跨資料庫所有權鏈接正常工作需要的。為了驗證SharedLoginAlaskaCity表上沒有SELECT許可,代碼嘗試從AlaskaCity直接讀取數據。但那個嘗試失敗了,因為SharedLoginChainedUserChainedDB任何對象上沒有許可。

 1 USE ChainedDB;
 2 GO
 3 CREATE USER ChainedUser FOR LOGIN SharedLogin;
 4 -- Note that we're not granting the user any permissions in the chained database.
 5 GO
 6 -- Verify that SharedLogin doesn't have direct access to the AlaskaCity table, even in the ChainedDB database context.
 7 EXECUTE AS LOGIN = 'SharedLogin';
 8 SELECT * FROM dbo.AlaskaCity;
 9 GO
10 REVERT;

代碼7.8:創建映射到在ChainedDBSharedLogin的用戶,但沒有任何許可,可以通過嘗試從AlaskaCity查詢數據

現在你可以執行代碼7.7,最後從視圖裡成功獲得數據。

你可以驗證跨資料庫所有權已經啟用,即使使用常見對象所有權,用戶在可以同時訪問兩個資料庫。你可以使用低嗎7.9關閉跨資料庫所有權鏈接——實際上你只要運行其中一個即可,因為只有2個資料庫都是啟用,跨資料庫所有權鏈接才可以正常工作——然後再次運行代碼7.7.這次你會得到剛纔一樣的錯誤。

1 ALTER DATABASE ChainedDB SET DB_CHAINING OFF;
2 ALTER DATABASE SourceDB SET DB_CHAINING OFF;
3 GO

代碼7.9:對2個資料庫關閉跨資料庫所有權鏈接

這是跨資料庫所有權鏈接要剋服的錯誤。

共同所有權

使用跨資料庫所有權鏈接啟用,代碼可以正常訪問視圖的原因是視圖和表有共同所有權——SharedLogin登錄。代碼假定你以sysadmin登錄到SSMS,因此在2個資料庫里所有創建的對象屬於dbo用戶,兩個都映射到sysadmin用戶。(跨資料庫所有權鏈接正常工作並不需要這個,這是讓代碼簡單和專註的一種方法)。你可以使用代碼7.10來驗證映射,它列出在資料庫里用戶資料庫和視圖的架構名稱,所有者用戶名和所有者登錄名。如果你在SourceDBChainedDB里運行代碼,你會發現OwnerLoginName是一樣的,如插圖7.3和插圖7.4所示,dbo用戶映射到sa登錄。

 1 SELECT
 2     so.[name] AS Object, 
 3     sc.[name] AS [Schema], 
 4     USER_NAME(COALESCE(so.principal_id, sc.principal_id)) AS OwnerUserName, 
 5     sp.name AS OwnerLoginName, 
 6     so.type_desc AS ObjectType 
 7 FROM sys.objects so 
 8     JOIN sys.schemas sc ON so.schema_id = sc.schema_id 
 9     JOIN sys.database_principals dp ON dp.principal_id         = COALESCE(so.principal_id, sc.principal_id)
10     LEFT JOIN master.sys.server_principals sp ON dp.sid = sp.sid
11 WHERE so.[type] IN ('U', 'V');  

代碼7.10:對於用戶資料庫和視圖,列出架構名,所有者用戶名和擁有者登錄名

插圖7.3:在SourceDB資料庫里運行代碼7.10的結果

插圖7.4:在ChainedDB資料庫里運行代碼7.10的結果

dbo用戶在一個資料庫里不是必須的,在另一個資料庫dbo用戶也不是必須的,理解這個非常重要。它們可以映射到完全不同的登錄或不映射。在鏈里,對於所有涉及到的對象,記錄的所有者有同個SID才是重要的。你可以使用代碼7.11來驗證對象擁有者的SID和登錄的SID是否一樣。(如果你想自己運行代碼的話,你會需要修改在最後部分的電腦名稱和用戶名)。

1 SELECT name, sid FROM SourceDB.sys.database_principals WHERE name = 'dbo'
2 UNION ALL
3 SELECT name, sid FROM ChainedDB.sys.database_principals WHERE name = 'dbo'
4 UNION ALL
5 SELECT 'PC201602202041\sa', SUSER_SID('PC201602202041\sa');

代碼7.11:驗證dbo用戶的SID是否和映射登錄的SID一樣

在的電腦上,代碼7.11的結果數據如插圖7.5所示。共同所有權!

插圖7.5:在SourceDB資料庫和ChainedDB資料庫里的dbo用戶SID,和在SSMS執行代碼的SID。

跨資料庫所有權鏈接風險

啟用跨資料庫所有權鏈接會有風險,因為有特殊地位用戶的許可權濫用。微軟描述了2個方式的風險,兩個都涉及了跨資料庫安全邊界的潛在風險。

  • 在單個資料庫的上下文里,資料庫擁有者,db_ddladmindb_owners資料庫角色的成員可以創建其它用戶擁有的對象。這些新對象可以在擁有同樣所有者的其它資料庫里使用對象,無意給了在其它資料庫的對象訪問。本質上來說,你應該在所有資料庫里信任這些特權用戶數據,取決於你在資料庫實例如何配置安全。
  • 有CREATE DATABASE許可的資料庫用戶可以創建新的資料庫或附加資料庫到資料庫實例。跨資料庫所有權鏈接啟用後,這些用戶可以從這些新建或附加的資料庫訪問在其它資料庫里的對象。

如果你想啟用跨資料庫所有權鏈接的話,這裡的關鍵是你要信任你特權的用戶,這些許可已經超過了在特定表裡簡單訪問和數據維護。這也是微軟為什麼強烈推薦的一個原因,如果你需要啟用跨資料庫所有權鏈接,為了控制安全風險,你只為需要的資料庫啟用。

小結

跨資料庫所有權鏈接還是你保持你數據安全的另一個方法。這些選項禁用的話,對於惡意用戶很難訪問其它資料庫的數據。當在正確的場景和安全的環境里,你可以啟用這個選項讓對象所有者保持它們數據的完全控制。你應該幾乎從不子啊伺服器級別啟用跨資料庫所有權鏈接。應該是,在只有真正需要的資料庫上啟用它,並確定保護好特權用戶的濫用。

原文鏈接:

http://www.sqlservercentral.com/articles/Stairway+Series/123545/ 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文會繼續深入學習OC記憶體管理,內容主要參考iOS高級編程,Objective C基礎教程,瘋狂iOS講義,是我學習記憶體管理的筆記 記憶體管理 1 記憶體管理的基本概念 1.1 Objective C中的記憶體管理 手動記憶體管理和自動釋放池 \ (Mannul Reference Counting) 自動 ...
  • 一 什麼是RunLoop? 從字面意思看就是運行迴圈,其實內部就是do-while迴圈,這個迴圈內部不斷地處理各種任務(比 如Source,Timer,Observer) 一個線程對應一個RunLoop,主線程的RunLoop預設已經啟動,子線程的RunLoop得手動啟動(run方法) RunLoo ...
  • 老師佈置了個作業:http://www.cnblogs.com/qingxu/p/5316897.html 作業中提到的 “玩了幾天以後,大家發現了一些很有意思的現象,比如黃金點在逐漸地往下移動。” 而只是提到而已,如果不保留歷史結果和不是比較明顯的顯示出來,大家也很難發現這個問題。於是我就想到了折 ...
  • 本文主要介紹EventBus3.0的源碼 EventBus是一個Android事件發佈/訂閱框架,通過解耦發佈者和訂閱者簡化 Android 事件傳遞。 EventBus使用簡單,並將事件發佈和訂閱充分解耦,從而使代碼更簡潔。 本文主要從以下幾個模塊來介紹 1、EventBus使用 2、EventB ...
  • 首先centos7 已經不支持mysql,因為收費了你懂得,所以內部集成了mariadb,而安裝mysql的話會和mariadb的文件衝突,所以需要先卸載掉mariadb,以下為卸載mariadb,安裝mysql的步驟。 #列出所有被安裝的rpm package rpm -qa | grep mar ...
  • SQL*PLUS 是oracle管理資料庫最常用的一個CMD界面,其中的幫助系統會給我們執行一些命令帶來快捷的指導和幫助,在oracle安裝時此功能是預設安裝的。有時候由於一些意外原因會失去此項功能,使用幫助系統會出現下麵的錯誤: SP2-0171: 幫助系統不可用。 以至於帶來很多的不便和麻煩。下 ...
  • 1. 分區表簡介使用分區表的主要目的,是為了改善大型表以及具有各種訪問模式的表的可伸縮性和可管理性。 大型表:數據量巨大的表。 訪問模式:因目的不同,需訪問的不同的數據行集,每種目的的訪問可以稱之為一種訪問模式。分區一方面可以將數據分為更小、更易管理的部分,為提高性能起到一定的作用;另一方面,對 ...
  • 1、內連接(等值連接) 示例:將連個表內容連接顯示 註意:只有當d.deptno = e.deptno條件滿足,內容才會顯示,否則不顯示 2 、外連接:讓等值判斷左右兩邊有一邊的數據可以全部顯示出來,使用外連接方式時使用”(+)” 格式: 左外連接:欄位=欄位(+) 右外連接:欄位(+)=欄位 示例 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...