構建和實現單點登錄解決方案(轉載于IBMdeveloperWorks)

將一個開放源碼的基于 Java 的身份驗證組件集成進 Web 門戶中

在現有的應用程序中實現單點登錄解決方案(single sign-on,SSO,即登錄一次,就可以向所有網絡資源驗證用戶的身份)是非常困難的,但是在構建復雜的門戶時,每個開發人員都要面對這個問題。因為門戶需要與后端資源集成,而每個后端資源都有自己的身份驗證需求,所以門戶常常必須向用戶提供單點登錄特性。在本文中,Chris Dunne 一步步地描述了他為一個 Web 門戶構建單點登錄解決方案的經歷。他將講解如何設置一個開放源碼解決方案(來自 Yale University 的 Central Authentication Service),以及如何將它擴展為根據 Microsoft Active Directory 基礎設施進行身份驗證。

我在自己的工作中發現,對各種門戶應用程序的需求正在增長。門戶的技術和功能性需求變得越來越復雜了。盡管出現了可以構建簡單門戶的工具,但是門戶與遠程或遺留數據源的集成問題仍然不容易解決。其中一個問題就是身份驗證。

身份驗證是個復雜的問題。門戶需要向后端數據源和應用程序驗證用戶的身份,但是這些應用程序可能具有互不相同的底層安全基礎設施。理想的最高效的身份驗證解決方案是單點登錄(single sign-on,SSO)?解決方案;在這種解決方案中,用戶只需要登錄一次,就可以向所有網絡資源驗證他的身份。

最近,在構建一個需要 SSO 的教育門戶時,我研究了許多商業的和開放源碼的 SSO 解決方案。在本文中,我將一步步地介紹使用免費的 SSO 實現(來自 Yale University 的 CAS)構建簡單 SSO 系統的過程。

為什么要選擇單點登錄?

有多少人實現過自己的身份驗證機制(常常是某種簡單的數據庫查詢)?您是否常常考慮創建和管理用戶帳號所需的工作流?在任何開發項目中,身份驗證都是很常見的任務。如果幸運的話,公司已經有一些通用的身份驗證類或庫。但是,這個任務常常被忽視,被當作只在后臺發生的微不足道的事情。

一般來說,公司往往沒有一致的身份驗證策略或可靠的身份驗證框架。隨著時間的推移,這會導致大量應用程序具有自己的身份驗證需求和用戶存儲庫。每個人都需要記住多個用戶名和密碼,才能訪問網絡上的不同應用程序。這給管理和支持部門帶來很大的負擔 —— 必須在每個應用程序中為每個職員設置帳號,當用戶忘記密碼時還要幫助他們解決問題,等等。

身份驗證是多種應用程序、平臺和基礎設施共有的需求。一般來說,一個用戶應該不需要多個用戶名。理想情況下,他應該只需要證明自己的身份一次,然后就能夠訪問所有已經得到授權的網絡資源。

SSO 的目標是,讓用戶能夠通過一次登錄訪問所有應用程序。它提供一個統一的機制來管理用戶的身份驗證,并實現業務規則來決定用戶對應用程序和數據的訪問。

在討論單點登錄的技術細節之前,先談談單點登錄的一些好處和風險。好處包括:

  • 提高用戶的效率。用戶不再被多次登錄困擾,也不需要記住多個 ID 和密碼。另外,用戶忘記密碼并求助于支持人員的情況也會減少。
  • 提高開發人員的效率。SSO 為開發人員提供了一個通用的身份驗證框架。實際上,如果 SSO 機制是獨立的,那么開發人員就完全不需要為身份驗證操心。他們可以假設,只要對應用程序的請求附帶一個用戶名,身份驗證就已經完成了。
  • 簡化管理。如果應用程序加入了單點登錄協議,管理用戶帳號的負擔就會減輕。簡化的程度取決于應用程序,因為 SSO 只處理身份驗證。所以,應用程序可能仍然需要設置用戶的屬性(比如訪問特權)。

對于單點登錄,經常提到的一些問題包括:

  • 難以重構。對 SSO 解決方案進行重構來適應現有的應用程序很困難,很耗費時間而且昂貴。
  • 無人看守的桌面。實現 SSO 會減少一些安全風險,但是也增加了其他安全風險。例如,如果用戶登錄之后離開了他的機器,惡意用戶就可以訪問他的資源。盡管這是一個普遍存在的安全問題,但是 SSO 會使這個問題更加嚴重,因為惡意用戶可以訪問所有獲得授權的資源。在采用多次登錄方式時,用戶每次只能登錄進一個系統,所以只有一個資源被泄露。
  • 單點攻擊。在使用單點登錄時,所有應用程序使用一個集中的身份驗證服務。對于希望實施拒絕服務攻擊的黑客,這是一個有吸引力的目標。

所以,SSO 并非毫無缺點。但是我相信,在用戶、管理員和開發人員看來,它的優點要超過缺點。

SSO 開放源碼項目

正如前面提到的,我當前正在為一個教育機構構建 Web 門戶。這個門戶將為參與遠程課程的學生提供一個在線學習環境。

這個門戶的構造塊已經就位了。站點已經建立了,課程內容已經開發出來了,虛擬學習環境也就位了,輔助應用程序(比如日記、日歷、電子郵件和筆記本)已經構建好或已經取得。所有這些組件都正在由學生使用,而且每個應用程序都運行在自己的服務器上。

客戶現在希望能夠通過 Web 瀏覽器遠程訪問這些應用程序,所以要構建一個門戶來提供訪問應用程序的單一入口,門戶應該向用戶提供單點登錄功能。用戶登錄進門戶之后,對他的身份進行驗證,然后他就能夠訪問門戶中所有已授權的資源。

我決定搜索一下關于如何實現 SSO 方案的信息,尋找有幫助的白皮書、產品和開放源碼項目。我使用以下條件來限制搜索的范圍:

  • Java 實現。這個門戶應用程序基礎設施是基于 Java 的,所以我希望 SSO 實現也是基于 Java 語言的。
  • 容易實現。在這個場景中,容易實現是指不需要對基礎設施或現有的應用程序做大量修改。
  • 其效果已經得到證明。它應該已經被一些大型組織采用,而且仍然處于活躍的開發階段。
  • 與 LDAP 兼容。我們的客戶使用 Microsoft Active Directory Server,所以我需要系統能夠輕松地根據 ADS 進行身份驗證。

我很高興地發現了幾個出色的開放源碼項目。(參見?參考資料?中的列表。)

我開始使用來自 Yale University 的 CAS(Central Authentication Service)系統開發一個原型,因為它滿足我的所有條件。它是基于 Java 的,源代碼是開放的。只需使用 JSP 標記和 servlet 過濾器,就能夠相當輕松地在 Java 應用程序環境中實現它。Yale University 正在使用它,這說明它的品質滿足我的條件。它還允許輕松地改變或擴展實際的身份驗證機制(無論是查詢數據庫還是 LDAP 服務器上的用戶名和密碼)。

CAS 概述

注意,在采用 CAS 協議時,應用程序不會看到用戶的密碼。CAS 服務器執行身份驗證,只有它能夠看到用戶的密碼。這會增強安全性,因為用戶名和密碼并不通過網絡傳遞給其他應用程序。

下圖說明了在集成了 CAS 服務器的系統中身份驗證是如何執行的。

圖 1. CAS 協議如何執行身份驗證

CAS 協議如何執行身份驗證

下面是這個身份驗證協議中的主要步驟。

  1. 用戶嘗試使用應用程序的 URL 訪問應用程序。用戶被重定向到 CAS 登錄 URL,采用的是 HTTPS 連接,他請求的服務的名稱作為參數傳遞。這時向用戶顯示一個用戶名/密碼對話框。
  2. 用戶輸入 ID 和密碼,CAS 對他進行身份驗證。如果身份驗證失敗,目標應用程序根本不會知道這個用戶曾經試圖訪問它 —— 用戶在 CAS 服務器上就被攔住了。
  3. 如果身份驗證成功,CAS 就將用戶重定向回目標應用程序,并在 URL 中附加一個稱為?ticket?的參數。然后,CAS 嘗試創建一個稱為?ticket-granting cookie?的內存 cookie。這是為了以后進行自動的重新驗證;如果存在這個 cookie,就表示這個用戶已經成功地登錄了,用戶就不需要再次輸入他的用戶名和密碼。
  4. 然后,應用程序要檢查這個 ticket 是否正確,以及是否代表一個有效用戶;檢查的方法是,打開一個 HTTPS 連接來調用 CASserviceValidate?URL,并作為參數傳遞 ticket 和服務名稱。CAS 檢查這個 ticket 是否有效,以及是否與請求的服務相關聯。如果檢查成功,CAS 就將用戶名返回給應用程序。

如果采用 Servlet 2.3 規范進行開發,那么甚至不需要為這些步驟操心。一個 servlet 過濾器會處理整個協議。您要做的只是在 web.xml 文件中配置過濾器參數。我就采用這種方式 —— 它意味著對門戶中應用程序代碼的修改非常少。

對 CAS 的深入討論超出了本文的范圍,我建議您閱讀?參考資料?中列出的來自 Yale University 的文章,從而判斷這種身份驗證方案是否滿足您的需要。

CAS 入門

設置 CAS 軟件是非常簡單的,但是在開始設置之前,您應該了解我用的一些軟件。我只用 Tomcat 4.1、Java Development Kit 1.4 和 Ant 1.5 測試了 CAS。(可以從?參考資料?下載這里提到的文件和客戶機庫。)

首先,下載 CAS 服務器和客戶機庫。已經針對許多語言和環境開發了客戶機庫,包括 Java、ASP、Perl、PHP 和 PL/SQL。

CAS 使用 HTTPS,所以必須在 Tomcat 中啟用這個功能。我發現這需要點兒技巧,但是如果按照我提供的說明(readme_tomcat_ssl.txt 文件)去做,應該不困難。

對 CAS 服務器 ZIP 文件進行解壓,并使用 Ant 構建腳本構建 CAS 服務器軟件。將 WAR 文件(Web Archives)部署到 Tomcat 的?/webapps?目錄中。在啟動 Tomcat 時,用 WAR 文件在?Tomcat/webapps?中創建一個 CAS 目錄。

下載 CAS 客戶機庫。對 ZIP 文件進行解壓,就會看到許多目錄。我要使用的是 Java 客戶機庫。同樣,也提供了 Ant 構建腳本。運行這個構建腳本。這會生成一個稱為 casclient.jar 的 JAR 文件。將這個文件復制到 Tomcat 根目錄下的?common/lib?目錄中。

現在,需要配置應用程序來使用 CAS。本文中用來進行演示的應用程序是 Tomcat 提供的可靠的 “HelloWorld” servlet 示例。這個應用程序應該在 Tomcat 系統中的?/webapps/examples?目錄下面。修改 web.xml 文件來配置 servlet 過濾器。

HelloWorld JSP 的 web.xml 文件包含下面的 servlet 過濾器配置。它對 HTTPS 使用本地主機和端口 8443。根據自己的配置修改這些設置。我提供的 zip 文件中包含一個 web.xml 文件示例。

清單 1. HelloWorld JSP 的默認 servlet 過濾器配置
<filter><filter-name>CAS Filter</filter-name><filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class><init-param><param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name><param-value>https://localhost:8443/cas/login</param-value></init-param><init-param><param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name><param-value>https://localhost:8443/cas/proxyValidate</param-value></init-param><init-param><param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name><param-value>localhost</param-value></init-param></filter><filter-mapping><filter-name>CAS Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

啟動 Tomcat。然后輸入 URL?http://localhost/examples/servlet/HelloWorldExample。這時會重定向到 CAS 登錄屏幕。默認的身份驗證器只要求為用戶名和密碼提供相同的字符串,例如在兩個域中都輸入?demo。然后,就會重定向到 HelloWorld 頁面。

這只是個簡單的 CAS 演示,但是它說明,通過使用這個強大的 servlet 過濾器,讓現有的 Java servlet 應用程序使用 CAS 是多么容易。還可以使用 JSP 標記集替代 servlet 過濾器,這種方法適合那些無法使用 servlet 過濾器的應用程序或應用服務器。

Active Directory Server 身份驗證

在我的教育門戶項目中,可以很輕松地修改應用程序,因為我能夠得到源代碼。我在每個應用程序中使用了 servlet 過濾器。在這種情況下,當用戶首次訪問門戶并請求一個受限制的應用程序或數據源時,CAS 將執行身份驗證。身份驗證成功之后,CAS servlet 過濾器可以檢查 ticket,并將用戶名作為參數傳遞給請求的應用程序。我修改了現有的應用程序登錄屏幕,讓它們在成功的身份驗證之后從 CAS 接收用戶名參數。然后,應用程序可以使用這個參數對用戶進行授權,并對用戶的活動進行審計記錄。

但是,CAS 本身沒有附帶任何真正有用的身份驗證器。默認的身份驗證器僅僅檢查用戶名和密碼是否相同。在教育門戶項目中,我使用 Microsoft 的 Active Directory Server 存儲用戶的個人信息。所以我需要擴展 CAS 服務器,讓它根據 Active Directory Server 檢查用戶名和密碼。

Yale University 的 CAS 設計人員開發了一個可插入的身份驗證器架構。通過擴展?PasswordHandler?接口,開發人員可以創建一個類來實現密碼檢查邏輯。

清單 2. CAS 的可插入身份驗證器架構
/** Interface for password-based authentication handlers. */
public interface PasswordHandler extends AuthHandler {/*** Authenticates the given username/password pair, returning true* on success and false on failure.*/boolean authenticate(javax.servlet.ServletRequest request,String username,String password);}

我要做的只是了解如何使用 Active Directory Server 檢查用戶名和密碼,創建一個類來擴展這個接口,并添加執行身份驗證的代碼。

ADS 是一種與 LDAP3 兼容的目錄服務器。它支持許多不同的身份驗證方法,主要包括匿名(anonymous)簡單(simple)?和SASL(Simple Authentication and Security Layer)。匿名身份驗證不適合我的項目;簡單身份驗證用明文發送密碼,這也不滿足需要。所以我使用 SASL。

SASL 支持可插入的身份驗證。這意味著可以對 LDAP 客戶機和服務器進行配置,讓它們相互協商并使用多種身份驗證機制之一。下面是當前定義的一部分 SASL 機制:

  • Anonymous
  • CRAM-MD5
  • Digest-MD5
  • External
  • Kerberos V4
  • Kerberos V5
  • SecurID
  • Secure Remote Password
  • S/Key
  • X.509

在這些機制中,流行的 LDAP 服務器(比如 Sun、OpenLDAP 和 Microsoft 提供的服務器)都支持 External、Digest-MD5 和 Kerberos V5。

CAS 本身與 Kerberos 相似,它們有許多相同的概念,比如 ticket 和 ticket-granting ticket(在 CAS 中實際上稱為 ticket-granting cookie),它們的協議也是相似的。所以,選擇 Kerberos 機制似乎是很自然的。另外,添加對 Kerberos 身份驗證的支持讓 CAS 在未來的開發中能夠作為基于 Web 的 Kerberos 代理代表用戶,這使 CAS 能夠替用戶管理 Kerberos ticket 的所有方面。這意味著遠程用戶也可以使用相同的 Kerberos 身份驗證機制訪問本地和網絡資源。

Kerberos 協議已經內置在 ADS 和 Windows 2000/XP 中。Java Authentication and Authorization Service(JAAS)提供了 Kerberos Login Module 的一個實現(參考資料?中列出的一個教程詳細描述了如何建立一個示例應用程序)。精確地說,它是 GSS-API SASL 機制,但是它只為 LDAP3 服務器提供 Kerberos v5 身份驗證。

Kerberos 身份驗證是一個很簡單的過程(如果仔細地按照以下說明進行操作的話):

  1. 在 JAAS 配置文件中為應用程序類配置 Login Module。
    edu.yale.its.tp.cas.auth.provider.KerberosAuthHandler  
    {
    com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
    };
  2. 創建一個?LoginContext,傳遞執行身份驗證的類的名稱和?CallBackHandler?對象。
    LoginContext lc = new LoginContext(CASApp.class.getName(), new CASCallbackHandler());
  3. 調用?login()?方法來執行身份驗證。如果執行過程沒有異常,身份驗證就成功了。如果拋出了異常,那么這個異常會指出失敗的原因。

要想深入了解 Kerberos 身份驗證,建議您利用本文末尾的參考資料。(我還提供了自己的實現和配置文件,KerberosAuthHandler?和CASCallBackHandler。)

需要創建一個新的?PasswordHandler?實現,KerberosAuthHandler,它按照上面的方法根據使用 Kerberos v5 的 Active Directory Server 進行身份驗證。

清單 3. 創建新的 PasswordHandler 實現
public class KerberosAuthHandler implements PasswordHandler {public boolean authenticate(javax.servlet.ServletRequest request,String username,String password) {LoginContext lc = null;try {/* Set up the Callback handler, and initialise *//* the userid and password fields */CASCallbackHandler ch = new CASCallbackHandler();ch.setUserId(username);ch.setPassword(password);/* Initialise the login context - LoginModule configured *//* in cas_jaas.conf and *//* set to use Krb5LoginModule. */lc = new LoginContext(KerberosAuthHandler.class.getName(), ch);/* Perform the authentication */lc.login();} catch (LoginException le) {System.err.println("Authentication attempt failed" + le);return false;}return true;}
}

在創建?LoginContext?時,傳遞這個類名和?CASCallbackHandler?對象。JAAS 配置文件指定這個類使用的登錄模塊。

在調用?login()?方法時,登錄模塊知道為了進行身份驗證它需要從用戶/應用程序獲得哪些信息。在使用 Kerberos 時,它需要用戶名和密碼,所以它構造一個數組,其中包含兩個回調對象(NameCallback?和?PasswordCallback),然后調用?CallbackHandler?對象,這個對象決定如何執行這些回調并獲得用戶名和密碼。

我采用最簡單最有利的方式,使用?CallbackHandler?上的?setter?方法顯式地設置用戶 ID 和密碼。然后,CallbackHandler?將它們傳遞給NameCallback?和?PasswordCallback?對象。

清單 4. 用 setName (CASUserId) 和 setPassword (CASPassword) 設置 ID 和密碼
public class CASCallbackHandler implements CallbackHandler 
{private String CASUserId;private char [] CASPassword;public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException {for (int i = 0; i < callbacks.length; i++) {if (callbacks[i] instanceof NameCallback) {NameCallback cb = (NameCallback)callbacks[i];cb.setName(CASUserId);} else if (callbacks[i] instanceof PasswordCallback) {PasswordCallback cb = (PasswordCallback)callbacks[i];cb.setPassword(CASPassword);} else {throw new UnsupportedCallbackException(callbacks[i]);}}}public void setUserId(String userid){CASUserId = userid;}public void setPassword(String password){CASPassword = new char[password.length()];password.getChars(0, CASPassword.length, CASPassword, 0);}

下面要做的是讓 CAS 使用新的身份驗證處理器。方法是在?webapps/cas?中 CAS 服務器的 web.xml 文件中進行以下設置:

清單 5. 讓 CAS 使用新的身份驗證處理器
<!-- Authentication handler --><context-param><param-name>edu.yale.its.tp.cas.authHandler</param-name><param-value>edu.yale.its.tp.cas.auth.provider.KerberosAuthHandler</param-value></context-param>

ZIP 文件(參考資料?中的 KerberosAuthSrc.zip)中包含一個 web.xml 示例。

必須重新啟動 Tomcat,但是這一次還需要設置一些 Java 運行時屬性。對 ZIP 文件(KerberosAuthSrc.zip)進行解壓,并將文件 cas_jaas.conf、krb5.conf 和 setkerberosjvmoptions.bat 復制到?TOMCAT_HOME?目錄中。運行 setkerberosjvmoptions.bat,然后啟動 Tomcat。

現在,可以再用 HelloWorld 應用程序做實驗了。這一次,可以使用 Active Directory Server 中定義的有效的 Kerberos 用戶名和密碼對。

轉載于:https://www.cnblogs.com/lxchma/p/6428023.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284523.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284523.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284523.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分享一個基于Abp 和Yarp 開發的API網關項目

這個項目起源于去年公司相要嘗試用微服務構建項目,在網關的技術選型中,我們原本確認了ApiSix 網關,如果需要寫網關插件需要基于Lua腳本去寫,我和另外一個同事當時基于這個寫了一個簡單的插件,但是開發測試以及發布都很麻煩,而且使用Lua腳本作為插件的開發語言本身也不是我們強項…

羅振宇2022“時間的朋友”跨年演講全文稿(pdf)

2021年12月31日20:30&#xff0c;五糧液成都金融城演藝中心&#xff0c;羅振宇“時間的朋友”跨年演講如約而至。 羅胖曾發下大愿望&#xff1a;跨年演講要連辦二十年。今年是第七場&#xff0c;也是最特殊的一場&#xff0c;羅胖面對12000個空座位&#xff0c;用53個好故事&am…

08.LoT.UI 前后臺通用框架分解系列之——多樣的Tag選擇器

LOT.UI分解系列匯總&#xff1a;http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI開源地址如下&#xff1a;https://github.com/dunitian/LoTCodeBase/tree/master/LoTUI 這個必須說下&#xff0c;本來是用Bootstrap-Select做的&#xff0c;很漂亮&#xff0c;正好…

jquery文檔加載完畢后執行的幾種寫法

2019獨角獸企業重金招聘Python工程師標準>>> 1.js文檔加載完畢 標簽內 οnlοad"test()"window.οnlοadfunction(){}2.jquery文檔加載完畢 //方式1 $(document).ready(function(){//TODO }); //方式2 $(function(){//TODO }) //方式3 $(function($){//TO…

新型基礎測繪與實景三維中國建設技術文件【3】基礎地理實體空間身份編碼規則

基礎地理實體是新型基礎測繪產品體系中的核心成果&#xff0c;是推動基礎測繪工作轉型升級的關鍵。與現有的測繪地理信息數據不同&#xff0c;基礎地理實體具有多粒度、多模態、多層次&#xff0c;以及搭載結構化、半結構化和非結構化多樣化信息的鮮明特點。 基礎地理實體空間…

oracle 表 視圖 存儲過程 序列 job

table 表--delete tabledrop table Test1;-- Create tablecreate table TEST1(ID NUMBER,T_NAME VARCHAR2(100),DT DATE);-- 添加注釋comment on column TEST1.T_NAME is 名稱;--添加age字段alter table Test1 add (age NUMBER(8));--刪除字段alter table TABLE_NAME …

[轉]Docker 大勢已去,Podman 即將崛起

Podman Podman 什么是Podman&#xff1f;Podman和Docker的主要區別是什么&#xff1f;Podman的使用與docker有什么區別&#xff1f;Podman 常用命令 容器鏡像部署 PodmanPodman 加速器使用 Podman 運行一個容器列出運行的容器檢查正在運行的容器查看一個運行中容器的日志查看一…

基于Kubernetes v1.24.0的集群搭建(一)

一、寫在前面 K8S 1.24作為一個很重要的版本更新&#xff0c;它為我們提供了很多重要功能。該版本涉及46項增強功能&#xff1a;其中14項已升級為穩定版&#xff0c;15項進入beta階段&#xff0c;13項則剛剛進入alpha階段。此外&#xff0c;另有2項功能被棄用、2項功能被刪除。…

mvc設計模式和mvc框架的區別

一組概念需要先理解&#xff0c;因為后面需要用&#xff1a; 架構&#xff1a;簡單的說架構就是一個藍圖&#xff0c;是一種設計方案&#xff0c;將客戶的不同需求抽象成為抽象組件&#xff0c;并且能夠描述這些抽象組件之間的通信和調用。 框架&#xff1a;軟件框架是項目軟件…

新型基礎測繪與實景三維中國建設技術文件【4】基礎地理實體數據元數據

基礎地理實體數據是新型基礎測繪產品體系中的核心成果&#xff0c;為實現該數據的規范化管理和使用&#xff0c;編制基礎地理實體數據元數據技術文件。本文件規定了基礎地理實體數據元數據的基本要求和元數據內容&#xff0c;適用于二維表達形式、三維表達形式基礎地理實體數據…

思科三層交換機充當路由器實現全網互通

轉載于:https://blog.51cto.com/13568840/2059797

劍指offer編程題Java實現——面試題3二維數組中的查找

題目描述 在一個二維數組中&#xff0c;每一行都按照從左到右遞增的順序排序&#xff0c;每一列都按照從上到下遞增的順序排序。請完成一個函數&#xff0c;輸入這樣的一個二維數組和一個整數&#xff0c;判斷數組中是否含有該整數。下面是我實現的代碼&#xff0c;修改下類名(…

mpvue開發小程序分享朋友圈無法自定義標題解決方法

在node_modules里面找到mpvue&#xff0c;手動修改一下mpvue這個包下的index.js文件 // 用戶點擊右上角分享 到朋友圈 onShareTimeline: rootVueVM.$options.onShareTimeline? function (options) { return callHook$1(rootVueVM, onShareTimeline, options); } : null,找到 L…

【ArcGIS Pro微課1000例】0020:ArcGIS Pro中河流(曲線)、湖泊(水體色)圖例制作案例教程

相關閱讀:【ArcGIS微課1000例】0032:ArcGIS中河流(曲線)、湖泊(水體色)圖例制作案例教程 河流、湖泊的樣式設置功能在ArcGIS Pro得到了延續,本文講解ArcGIS Pro中河流湖泊圖例的設置方法。 《ArcGIS Pro從入門到精通系列精品教程(微課版)》專欄包括完整的實驗數據包,…

swift學習選pizza項目

2019獨角獸企業重金招聘Python工程師標準>>> 原文: https://makeapppie.com/2014/09/18/swift-swift-implementing-picker-views/ 效果: 步驟: 新建iOS single view application 名字為SwiftPickerViewPizzaDemo, 打開main storyboard選中view controoler, 右上角, …

Windows 11 新版 25163 推送!任務欄全新菜單、應用商店更新、文件資源管理器大量修復...

面向 Dev 頻道的 Windows 預覽體驗成員&#xff0c;微軟現已推送 Windows 11 預覽版 Build 25163。主要變化1.微軟宣布為 Windows 11 任務欄引入全新溢出體驗&#xff0c;當任務欄上的應用程序圖標或窗口達到任務欄容量上限時&#xff0c;將啟用全新溢出菜單。2.微軟更新了 Mic…

shell中source與sh區別

shell中使用source conf.sh&#xff0c;是直接運行conf.sh的命令&#xff0c;不創建子shell&#xff0c;類似與html中include&#xff0c;而sh是則創建子shell&#xff0c;子shell里面 的變量父shell無法使用&#xff0c;對環境變量的修改也不影響父shell。父shell中的局部變量…

[轉]Web3 是去中心化的“騙局”?

作者 | InvisibleUp 譯者 | 彎月 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; Web3 不是去中心化。 雖然我覺得這一點很明顯&#xff0c;根本不需要通過一篇文章來說明&#xff0c;但我也是迫不得已&#xff0c;因為突然之間各大科技巨頭&#xff0c;比如 Redd…

實景三維建設背景下,三維GIS面臨哪些挑戰?

2021年8月26日&#xff0c;自然資源部印發《實景三維中國建設技術大綱&#xff08;2021版&#xff09;》&#xff0c;明確指出“實景三維中國建設是落實數字中國、平安中國、數字經濟戰略的重要舉措&#xff0c;是落實國家新型基礎設施建設的具體部署&#xff0c;是服務生態文明…

無需編碼,自動實現“異步 Request-Reply”模式

前言上次&#xff0c;我們雖然用代碼實現了“異步 Request-Reply 模式”&#xff0c;但是需要為每一個長時間操作 API 實現一個對應的 AsyncXXX 操作。其實&#xff0c;可以嘗試用 Source Generators 減少這種重復性勞動。實現思路Controller 類必須是partial,這樣才能為它額外…