Spring Security –在一個應用程序中有兩個安全領域

這篇博客文章主要是關于Spring Security配置的。
更具體地說,它打算顯示如何在一個Web應用程序中配置兩個不同的安全領域。

第一安全領域是針對瀏覽器客戶端的。 它使我們能夠在登錄頁面中登錄并訪問受保護的資源。

第二安全領域旨在處理來自android應用程序的REST Web服務請求。 在每個請求上,REST客戶端應將所需的信息發送到服務器,并且此信息將用于確定是否應允許RESTfull請求通過。
這兩個安全領域(配置)的區別在于Web應用程序中資源的URL模式不同。 在這兩種配置中,我們都可以重用相同的身份驗證邏輯。

第一安全領域

我們有一個經典的Web應用程序,其中包含一些受保護的資源(頁面)。 為了訪問這些資源,用戶應在登錄頁面上登錄到應用程序。 如果登錄成功,則將用戶轉發到所請求的資源。 如果用戶的登錄過程由于某種原因(例如,錯誤的用戶名或密碼)而失敗,則該用戶將無法獲得受保護的資源,并且將其重定向到登錄頁面,并顯示相應的消息。
我在上一節中剛剛描述的情況可能被認為是“經典的Web應用程序行為”。 普通的互聯網用戶至少會遇到數百個這樣的在線應用程序。 這種行為旨在與客戶(瀏覽器)一起使用。 由于這種行為在當今非常普遍,因此Spring安全性使得實現它非常容易。 顯然,基于表單的身份驗證機制最適合我們。 在Spring Security中,當您希望定義與客戶端身份驗證狀態相關的操作時,可以定義入口點。 這是我們標準瀏覽器-客戶端入口點的預覽:

<http? entry-point-ref="loginUrlAuthenticationEntryPoint" use-expressions="true"><intercept-url pattern="/includes/content/administration.jsp" access="hasAnyRole('ROLE_100','ROLE_1000')" /><intercept-url pattern="/includes/content/userAdministration.jsp" access="hasAnyRole('ROLE_100','ROLE_1000')" /><intercept-url pattern="/includes/content/groupAdministration.jsp" access="hasAnyRole('ROLE_100','ROLE_1000')" /><intercept-url pattern="/includes/content/departmentAdministration.jsp" access="hasAnyRole('ROLE_100','ROLE_1000')" /><intercept-url pattern="/includes/content/shiftAdministration.jsp" access="hasAnyRole('ROLE_100','ROLE_101','ROLE_1000') /><custom-filter position="FORM_LOGIN_FILTER" ref="userAuthenticationProcessingFilter" /><logout logout-url='/logout' />
</http><beans:bean id="loginUrlAuthenticationEntryPoint"class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"><beans:property name="loginFormUrl" value="/login.jsp" />
</beans:bean>

希望這是不言而喻的。 loginUrlAuthenticationEntryPoint是一個入口點,您可以在其中配置實現了登錄功能的登錄頁面。 然后,在http元素中,我們將該入口點的行為配置為更多詳細信息。 首先,我們定義了攔截URL元素列表。 僅當請求了這些資源之一時,才會激活此入口點。 我們還用我們自己的自定義版本替換了默認的FORM_LOGIN_FILTER 。 Spring安全性通過應用您在入口點中定義的過濾器鏈來發揮作用。 這些基本上是標準的servlet過濾器。 您可以使用Spring預定義過濾器,也可以擴展它們并插入自定義過濾器。 在這里,我們使用了Spring的安全過濾器之一。

這是一個UsernamePasswordAuthenticationFilter 。 它用于具有用戶名和密碼字段的登錄頁面的情況。 該過濾器使我們能夠結合將用于身份驗證的自定義機制。 它還允許我們定義在成功和不成功的身份驗證的情況下將要采取的措施。 讓我們看看這種配置如何:

<beans:bean id="loginSuccessHandler"class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"><beans:property name="defaultTargetUrl" value="/main.jsp" />
</beans:bean><beans:bean id="userAuthenticationProcessingFilter"class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"><beans:property name="authenticationManager" ref="authenticationManager" /><beans:property name="authenticationFailureHandler"ref="loginMappingFailureHandler" /><beans:property name="authenticationSuccessHandler"ref="loginSuccessHandler" />
</beans:bean><beans:bean id="loginMappingFailureHandler"class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler"><beans:property name="exceptionMappings" ref="failureUrlMap" />
</beans:bean><util:map id="failureUrlMap" map-class="java.util.HashMap"><beans:entrykey="org.springframework.security.authentication.BadCredentialsException"value="/login.jsp?errorMessage=bad.credentials" /><beans:entrykey="org.springframework.security.authentication.DisabledException"value="/login.jsp?errorMessage=disabled.user" />
</util:map>

我們再來看一下此配置。 我將解釋我們在這里所做的事情。
首先,我們定義了表單登錄過濾器。 實際上,我們為此定義了三件事。 我們為它提供了自定義身份驗證機制,該機制將在整個應用程序中使用。 該機制通過authenticationManager插入到過濾器中。 我將很快談論認證管理器。

第二件事,我們定義了一個登錄失敗處理程序。 基本上,這是Spring異常以及對這些異常采取的措施的映射。 異常由AuthenticationProvider引發,如下所述。 例如,當用戶輸入錯誤的用戶名或密碼時,將引發BadCredentialsException 。 發生這種情況時,用戶將再次重定向到登錄頁面。 還將某些參數附加到登錄頁面的URL,以使我們能夠顯示正確的錯誤消息。

第三,也是最后一件事,我們定義了一個成功的身份驗證處理程序。 這確實很明顯。 我們正在定義如果登錄成功該怎么辦。 用戶被發送到主頁。

現在,讓我們來談談認證管理器。 這只是Spring使用的接口。 可以是任何東西。 它可以是用戶數據庫,LDAP服務器或其他數據庫。 身份驗證管理器不能自行完成工作。 它僅使用身份驗證提供程序為其執行實際的身份驗證工作。 身份驗證提供程序在被調用時可以做兩件事:

  1. 可以返回成功填充的對象(這是Spring的Authentication接口的實例)
  2. 可以拋出適當的Spring安全異常之一

身份驗證管理器配置如下所示:

<authentication-manager alias="authenticationManager"><authentication-provider ref="authenticationProvider" />
</authentication-manager><beans:bean id="authenticationProvider" class="ba.codecentric.medica.security.UserAuthenticationProvider"><beans:property name="userService" ref="userService"/><beans:property name="licenseInformationWrapper" ref="licenseInformationWrapper"/>
</beans:bean>

這是我的定制身份驗證提供程序的源代碼:

package ba.codecentric.medica.security;import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;import ba.codecentric.medica.administration.service.UserService;
import ba.codecentric.medica.model.Group;
import ba.codecentric.medica.model.LicenseInformationWrapper;
import ba.codecentric.medica.model.Role;
import ba.codecentric.medica.model.User;public class UserAuthenticationProvider implements AuthenticationProvider {private static final String ROLE_PREFIX = "ROLE_";private UserService userService;private LicenseInformationWrapper licenseInformationWrapper;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {User user = userService.getUserByUsernameAndPassword(authentication.getName(), authentication.getCredentials().toString(), true);if (user != null) {Collection authorities = new ArrayList(buildRolesFromUser(user));authorities.addAll(getActivatedModulesAsRoles());return new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(),authorities);} else {throw new BadCredentialsException("Try again");}}private Collection getActivatedModulesAsRoles() {List activatedModules = new ArrayList();if(CollectionUtils.isNotEmpty(licenseInformationWrapper.getActivatedModules())) {for(String activatedModuleName: licenseInformationWrapper.getActivatedModules()) {activatedModules.add(new SimpleGrantedAuthority(ROLE_PREFIX + activatedModuleName));}}return activatedModules;}private Collection buildRolesFromUser(User user) {Collection authorities = new HashSet();for (Group group : user.getGroups()) {for (Role role : group.getRoles()) {authorities.add(new SimpleGrantedAuthority(ROLE_PREFIX + role.getName()));}}return authorities;}@Overridepublic boolean supports(Class authentication) {return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));}public UserService getUserService() {return userService;}public void setUserService(UserService userService) {this.userService = userService;}public LicenseInformationWrapper getLicenseInformationWrapper() {return licenseInformationWrapper;}public void setLicenseInformationWrapper(LicenseInformationWrapper licenseInformationWrapper) {this.licenseInformationWrapper = licenseInformationWrapper;}}

如您所見,身份驗證過程非常簡單。 我的自定義身份驗證提供程序實現了Spring AuthenticationProvider接口。

就像我們之前討論的那樣,它可以完成工作。 它在數據庫的用戶表中查找用戶名和密碼。 如果找到這樣的用戶,則創建并返回認證對象。 否則,如果未找到此類用戶,則authenticate方法將引發適當的異常。 還有一件事情。 Spring使用GrantedAuthority對象的集合來表示分配給用戶的角色。 這就是為什么我們構建這樣的集合并將其附加到身份驗證對象的原因。 必須將數據庫中與用戶連接的每個角色都添加到已授予權限的集合中,以使Spring將此角色視為角色。 并且每個角色必須具有ROLE_前綴。 我們還有另一件事要展示。 如何從登錄網頁調用此過濾器? 這是login.jsp的一部分:

<form id="loginForm" method="POST" action="j_spring_security_check"><table>
<tr><td><b><fmt:message key="login.username.label" />:</b></td><c:choose><c:when test="${not empty param.j_username}" ><td><input type="text" name="j_username" id="username" value="${param.j_username }" class="loginInput" /></td>??? </c:when><c:otherwise><td><input type="text" name="j_username" id="username" class="loginInput"/></td></c:otherwise></c:choose> </tr>
<tr><td><b><fmt:message key="login.password.label" />:</b></td><c:choose><c:when test="${not empty param.j_password}" ><td><input type="password" name="j_password" id="password" value="${param.j_password }" class="loginInput" /></td>??? </c:when><c:otherwise><td><input type="password" name="j_password" id="password" class="loginInput" /></td></c:otherwise></c:choose> </tr>
<tr><td><b><fmt:message key="login.alphabet.label" /></b>:</td><td><select id="alphabet" class="fullWidth" onchange="languageSelect();"><option value="lat"><fmt:message key="login.alphabet.lat" /></option><option value="cir"><fmt:message key="login.alphabet.cyr" /></option></select></td></tr>
<tr><td></td><td><input type="submit" value="<fmt:message key="login.button.label" />" class="right"></td></tr>
</table></form>

默認情況下,標準Spring安全性設置要求您通過調用j_spring_security_check從登錄表單中調用安全鏈。 用戶名和密碼過濾器將攔截此URL(默認設置),但您可以將其配置為攔截任何其他URL。 好吧,這一切都與“基于瀏覽器的客戶端”安全領域有關。 如果用戶未登錄并嘗試訪問受該領域(入口點)保護的資源,則該領域將重定向用戶到登錄頁面并要求他登錄。只有當用戶登錄時,才受保護資源將可用。

第二安全領域

現在最后,讓我們討論應用程序中的第二個安全領域。 我們僅在博客的簡介部分提到了它。 該應用程序支持REST服務調用。 我們必須實現將應用程序的某些部分與運行在移動設備上的簡單android應用程序同步的要求。 我們認為最簡單的方法是從手機到Web應用程序進行RESTfull調用。 當然,我們在這里也需要安全。 我們不想讓用戶始終能夠連接到應用程序。 用戶列表及其角色在數據庫中維護。 例如,某個用戶今天可以處于活動狀態,但是明天管理員可以決定該用戶不再處于活動狀態,并且不應該能夠連接到應用程序(也應該不能登錄)。 因此,必須在REST服務領域中實現安全性。

讓我們考慮一下這個領域。 這些REST調用應該如何工作。 Android應用程序將POST請求(RESTfull請求)發送到Web應用程序以獲取某些數據(醫生的約會等)。 應用程序查找并返回請求的數據。 然后,Android應用程序處理獲取的數據并將其顯示給用戶。

現在,我們將安全性添加到此RESTfull概念中,并嘗試用安全性描述概念。 Android應用程序發送POST請求。 Android應用程序發送一個包含哈希用戶名和密碼的標頭,作為每個請求的一部分(請參閱-> 基本身份驗證 )。

Web應用程序的安全領域(入口點)應該接收到此請求,并且如果用戶名和密碼確實是活動用戶,則允許此請求到達Web應用程序中的REST服務,并將對其進行處理。 如果用戶名和密碼無效(或用戶處于非活動狀態),則請求應在安全入口點失敗,這意味著我們應立即返回格式正確的HTTP響應,該響應將通知客戶端應用程序該用戶與該用戶名稱和密碼不允許訪問Web應用程序中的REST服務。

正如我們在這種情況下所看到的,先前定義的入口點的行為與REST服務不對應。 上一個入口點,如果用戶未通過身份驗證,則將其重定向到登錄頁面。 這意味著,如果用戶未通過身份驗證,則服務器實際上會返回包含登錄頁面HTML代碼的HTTP響應。 我們無法在android應用程序中處理這種行為,因為它不會顯示任何HTML網頁。 那么,當它收到登錄頁面HTML時會怎么做?
這就是為什么我們實際上需要Web應用程序中的第二個安全域(安全性入口點)的主要原因,該安全域的工作方式不同于處理瀏覽器客戶端的機制。 如果用戶無法通過身份驗證,此新的安全領域將僅將格式正確的HTTP響應返回給客戶端應用程序(它將在響應上設置特定的HTTP狀態和HTTP消息)。 我們知道,在Java Server環境中,我們有一種稱為基本身份驗證的安全性。 它基于發送散列的用戶名和密碼作為請求標頭的一部分(標頭必須以特定方式進行格式化)。 然后,如果可以在用戶數據池中找到用戶名和密碼,則允許通過請求。 否則,將返回HTTP響應以及相應的狀態和消息,以告知客戶端不允許其訪問某些資源。 對我們來說幸運的是,Spring支持這種身份驗證機制。 我們將添加另一個入口點和一個過濾器。 它將是這樣的:

<http entry-point-ref="basicAuthEntryPoint" pattern="/ws/**" use-expressions="true"><intercept-url pattern="/ws/schedule/patients" access="hasAnyRole('ROLE_1','ROLE_100','ROLE_300','ROLE_1000')" /><custom-filter ref="basicAuthenticationFilter" after="BASIC_AUTH_FILTER" />
</http><beans:bean id="basicAuthEntryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint"><beans:property name="realmName" value="REST Realm" />
</beans:bean><beans:bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"><beans:property name="authenticationManager" ref="authenticationManager"/><beans:property name="authenticationEntryPoint" ref="basicAuthEntryPoint" />
</beans:bean>

基本上,我們添加了一個新的入口點(安全領域),該入口點攔截URL路徑/ ws / **上的所有請求。 這是我們所有REST服務調用通過的路徑。 我們使用了Springs BasicAuthenticationFilter ,它提供了讀取請求標頭和調用身份驗證管理器的功能。 如果在數據庫中找到了用戶名和密碼(由身份驗證管理器處理),將允許請求進一步傳遞。 如果在數據庫中找不到用戶名和密碼,入口點將在HTTP響應上設置狀態401,并立即將此響應返回給客戶端。 這只是我們Android應用程序所需的行為。

這就是我們的應用程序需要的所有安全配置。 現在剩下要做的就是在web.xml文件中啟用Spring安全過濾器。 我已經提到過,Spring安全性可以通過在請求上調用過濾器鏈來實現。 這意味著存在某種“主”過濾器,它是所有其他后續過濾器和服務的基礎。 在web.xml中啟用并配置了該“主”過濾器。 這是我的配置:

<filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern><dispatcher>ERROR</dispatcher><dispatcher>REQUEST</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>FORWARD</dispatcher>
</filter-mapping>

如您所見,主要的Spring安全過濾器已配置為攔截對應用程序中所有資源的所有請求。 但是,哪些資源真正受到保護,哪些資源是公共資源,則由入口點控制(通過http元素中的URL模式)。 例如,位于/ css文件夾中的所有資源都被視為公用資源,不需要用戶進行身份驗證就可以訪問它們:

<http pattern="/css/**" security="none" />

另一方面,像管理頁面這樣的資源受到保護,并且如果用戶希望訪問該頁面,則不僅要求用戶進行身份驗證,還需要分配某些角色。 這是此xml代碼段中的示例:

<!-- more xml -->
<intercept-url pattern="/includes/content/administration.jsp" access="hasAnyRole('ROLE_100','ROLE_1000')" />
<!-- more xml -->

還有兩件事要說!

當您的安全配置中有多個http元素時,請確保具有最特定模式屬性的元素位于不那么特定甚至可能沒有模式屬性的元素之前。 否則,當Spring開始抱怨應用程序中的過濾器排序沒有意義時,您將在日志文件中看到很長的堆棧跟蹤。

閱讀此博客后,您可能會開始認為添加基于表單的身份驗證或基本身份驗證就足夠了,您的應用程序將是安全的。 但是,那不是完全正確的。 任何對HTTP協議和網絡具有“技術”知識的人都可以想到如何在網絡內部攔截HTTP數據流的方式。 對于基本身份驗證和基于表單的身份驗證,諸如用戶名和密碼之類的信息直接通過HTTP協議發送。 對于基本身份驗證,它們將作為HTTP請求標頭發送。 對于基于表單的身份驗證,它們將作為請求參數發送。 因此,可以攔截和讀取這些HTTP流的人員可以輕松讀取您的標頭并請求參數。 稍后,同一個人可以手動創建請求,并將那些標頭或參數附加到請求。 當然,此新請求現在將由容器授權,因為它包含正確的身份驗證詳細信息。

那么,我們該怎么做才能避免對應用程序的這些安全攻擊?
真正的答案是:我們應該在保護應用程序資源的地方使用HTTPS協議 。 僅通過使用HTTPS協議和Java服務器的身份驗證機制,我們就可以肯定地說我們的應用程序確實是安全的。

參考: Spring Security –我們的JCG合作伙伴 Branislav Vidovi提供了一個應用程序中的兩個安全領域 ? 在極客的東西:-)博客上。


翻譯自: https://www.javacodegeeks.com/2012/08/spring-security-two-security-realms-in.html

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

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

相關文章

基于Activiti工作流引擎實現的請假審核流程

概要 本文檔介紹的是某商用中集成的Activiti工作流的部署及使用&#xff0c;該框架用的Activiti版本為5.19.0。本文檔中主要以一個請假流程為例子進行說明&#xff0c;該例子的流程圖如下&#xff1a; 這是一個可以正常運作的工作流業務了&#xff0c;但是它也有不足的地方&…

linux編譯ffmpeg成so,「ffmpeg」一 mac 環境下編譯ffmpeg,生成so庫文件

1.下載ffmpeg源碼,官網&#xff0c;我這里直接采用git 方式下載&#xff1a;下載ffmpeg.png終端輸入git命令&#xff1a;靜靜等待~最后下載的版本為3.4.6 。image.png這里注意一下&#xff0c;剛開始我用的ndk版本是ndk-17b&#xff0c;在編譯該版本的ffmpeg時始終失敗&#xf…

4Web Service中的幾個重要術語

4.1WSDL: web service definition language 直譯:Webservice定義語言 1.對應一種類型的文件.wsdl 2.定義了webservice的服務端與客戶端應用交互傳遞請求和響應數據的格式和方式 3.一個webservice對應一個唯一的esdl文檔 4.2SOAP: simple object access protocal 直譯:簡單對象訪…

云端:亞馬遜,谷歌應用引擎,Windows Azure,Heroku,Jelastic

您想在云端嗎&#xff1f; 您有很多選擇。 我已經評估或使用了許多方法&#xff0c;因此這里有幾句話。 &#xff08;當我使用Java時&#xff0c;我將包括一些與Java相關的注釋&#xff0c;但大多數情況適用于所有&#xff08;受支持的&#xff09;語言。&#xff09; 但是在深…

JS-字符串操作-替換

<!DOCTYPE HTML><html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8"><title>無標題文檔</title><style>p { border:10px solid #ccc; background:#FFC; width:400px; padding:20px;…

linux下kegg注釋軟件,KEGG數據中全部代謝反應和代謝物注釋信息的下載

# 加載函數與R包 -----------------------------------------------------------------library(KEGGREST)library(plyr)source("./RbioRXN-master/RbioRXN-master/R/get.kegg.all.R")source("./RbioRXN-master/RbioRXN-master/R/get.kegg.byId.R")## KEGG數…

java常見異常

算術異常類&#xff1a;ArithmeticExecption空指針異常類&#xff1a;NullPointerException 類型強制轉換異常&#xff1a;ClassCastException 數組負下標異常&#xff1a;NegativeArrayException 數組下標越界異常&#xff1a;ArrayIndexOutOfBoundsException 違背安全原則異常…

Spring Security 3 Ajax登錄–訪問受保護的資源

我看過一些有關Spring Security 3 Ajax登錄的博客&#xff0c;但是我找不到解決如何調用基于Ajax的登錄的博客&#xff0c;匿名用戶正在Ajax中訪問受保護的資源。 問題 – Web應用程序允許匿名訪問某些部分&#xff0c;并且某些部分是受保護的資源&#xff0c;需要用戶登錄。 …

測試環境下將centos6.8升級到centos7的操作記錄(轉)

在測試環境下安裝openstack&#xff0c;由于在centos6下安裝openstack&#xff0c;針對源的問題有很多&#xff0c;安裝起來很不順利&#xff01; 但是在centos7下安裝卻很順利&#xff0c;所以考慮將服務器由centos6升級到centos7 這個我是在測試機中運行的&#xff0c;建議不…

linux運維選擇題,初學Linux練習題

1、將/etc/issue文件中的內容轉換為大寫后保存至/tmp/issue.out文件中tr ‘a-z’ ‘A-Z’ < /etc/issue > /tmp/issue.out2、將當前系統登錄用戶的信息轉換為大寫后保存至/tmp/who.out文件中3、一個linux用戶給root發郵件&#xff0c;要求郵件標題為”help”&#xff0c…

[轉]Web Api系列教程第2季(OData篇)(二)——使用Web Api創建只讀的OData服務

本文轉自&#xff1a;http://www.cnblogs.com/fzrain/p/3923727.html 前言 很久沒更新了&#xff0c;之前有很多事情&#xff0c;所以拖了很久&#xff0c;非常抱歉。好了&#xff0c;廢話不多說&#xff0c;下面開始正題。本篇仍然使用上一季的的項目背景&#xff08;系列地址…

使用Spring 3 MVC處理表單

本文是有關Spring 3的一系列文章的一部分。該系列的上一篇文章可以在此處獲得 。 在本文中&#xff0c;我們向Spring MVC邁出了又一步。 [此外&#xff1a; 術語MVC的創建者提供的pdf 。]從上一篇文章構建&#xff0c;讓我們添加將“聯系人”添加到應用程序所需的代碼。 首先&a…

插入排序法之——直接插入排序、折半插入排序、希爾排序

// test20.cpp : 定義控制臺應用程序的入口點。 // #include "stdafx.h" #include<iostream> #include<vector> #include<string> #include<queue> #include<stack> #include<cstring> #include<string.h> #include<de…

linux idea 快捷鍵,Linux 下 IDEA 的 Ctrl+Alt+S

前言這是個困擾我一年多的問題&#xff0c;今天終于解決了……起因一年前將主系統換成 Arch Linux 后&#xff0c;其他一切正常就是 IDEA 的打開設置的快捷鍵 ctrlalts 失效&#xff0c;讓我很是頭疼。雖然不是很重要&#xff0c;但是對于我這種強迫癥來說別提多難受了……我曾…

修改input的placeholder顏色

1、CSS選擇器 因為每個瀏覽器的CSS選擇器有所差異&#xff0c;所以需要針對每個瀏覽器做單獨的設定。 ::-webkit-input-placeholder { /* WebKit browsers */ color: #999; } :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #999; } ::-moz-placeholder { /* Mozil…

解決Spring自動裝配中的循環依賴

我認為這篇文章是在企業應用程序開發中使用Spring的最佳實踐。 使用Spring編寫企業Web應用程序時&#xff0c;服務層中的服務量可能會增加。 服務層中的每個服務可能會消耗其他服務&#xff0c;這些服務將通過Autowire注入。 問題&#xff1a;當服務數量開始增加時&#xff0…

01.MD5加密

namespace _01.MD5加密{ class Program { static void Main(string[] args) { //MD5加密就是給想要的密碼或者其它字符加密 //如果字符串被加密成MD5值之后,是不可逆的. //字符串123 的MD5 64位加密形式是 202cb962ac59075b964b07152d234b70 Console.WriteLine("請輸入需要…

C語言數字3轉變字符 3 程序,大學c語言知識點總結

大學c語言知識點總結C語言的設計目標是提供一種能以簡易的方式編譯、處理低級存儲器、產生少量的機器碼以及不需要任何運行環境支持便能運行的編程語言。一起來看看大學c語言知識點總結吧!大學c語言知識點總結1、編譯預處理不是C語言的一部分&#xff0c;不再運行時間。C語言編…

接觸Jenkins(Hudson)API,第1部分

哪一個-哈德森還是詹金斯&#xff1f; 都。 幾個月前&#xff0c;我開始使用Hudson v1.395來從事這個小項目&#xff0c;在出現巨大分歧之后又回到了這個項目。 我以此為契機&#xff0c;看我將來選擇永久搬到詹金斯時是否會遇到任何重大問題。 有很多麻煩-最值得注意的是&…

使用javascript模擬常見數據結構(四)

七、樹 樹是一種非線性的分層的數據結構&#xff0c;在現實生活中比較常見的例子比如家譜和公司的組織架構圖&#xff0c;如下所示&#xff1a; 一個樹結構存在著一系列的父子結構&#xff0c;并且有著一個根節點&#xff0c;這種結構本質上表明了一對多的關系。 那&#xff0c…