Spring 3,Spring Web Services 2和LDAP安全

今年的開局很好,其中另一個“截止日期不會改變” /“跳過所有繁文tape節” / “狂野西部”類型的項目中,我必須弄清楚并使用相對而言實現一些功能。新的庫和技術需要進行更改,Spring 3并不是新增功能,但是在Java 5,weblogic 10(.01)和Spring 2.5.6緩慢的企業環境中,它是相對的。

由于一般的時間限制,我在這篇文章中沒有過多地介紹“ fluff”,只是使用多個XSD和LDAP安全性來創建和保護Spring 3,Spring WS 2 Web服務。

編碼:

服務端點:ExampleServiceEndpoint
這是將在后面的配置中使用Web服務公開的類。

package javaitzen.spring.ws;import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;import javax.annotation.Resource;@Endpoint
public class ExampleServiceEndpoint {private static final String NAMESPACE_URI = "http://www.briandupreez.net";/*** Autowire a POJO to handle the business logic@Resource(name = "businessComponent")private ComponentInterface businessComponent;*/public ExampleServiceEndpoint() {System.out.println(">>  javaitzen.spring.ws.ExampleServiceEndpoint loaded.");}@PayloadRoot(localPart = "ProcessExample1Request", namespace = NAMESPACE_URI + "/example1")@ResponsePayloadpublic Example1Response processExample1Request(@RequestPayload final Example1 request) {System.out.println(">> process example request1 ran.");return new Example1Response();}@PayloadRoot(localPart = "ProcessExample2Request", namespace = NAMESPACE_URI + "/example2")@ResponsePayloadpublic Example2Response processExample2Request(@RequestPayload final Example2 request) {System.out.println(">> process example request2 ran.");return new Example2Response();}}

代碼:CustomValidationCallbackHandler

這是我編寫的用于擴展AbstactCallbackHandler的自定義代碼,它允許我們使用LDAP。
根據下面的CallbackHandler中的注釋,根據安全性/性能考慮,最好有一個緩存管理器(如Hazelcast或Ehcache)來緩存經過身份驗證的用戶。

下面的Digest Validator可以直接從Sun庫中使用,我只是想了解它是如何工作的。

package javaitzen.spring.ws;import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import com.sun.xml.wss.impl.misc.Base64;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.Properties;public class CustomValidationCallbackHandler extends AbstractCallbackHandler implements InitializingBean {private Properties users = new Properties();private AuthenticationManager ldapAuthenticationManager;@Overrideprotected void handleInternal(final Callback callback) throws IOException, UnsupportedCallbackException {if (callback instanceof PasswordValidationCallback) {final PasswordValidationCallback passwordCallback = (PasswordValidationCallback) callback;if (passwordCallback.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {final PasswordValidationCallback.DigestPasswordRequest digestPasswordRequest =(PasswordValidationCallback.DigestPasswordRequest) passwordCallback.getRequest();final String password = users.getProperty(digestPasswordRequest.getUsername());digestPasswordRequest.setPassword(password);passwordCallback.setValidator(new CustomDigestPasswordValidator());}if (passwordCallback.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {passwordCallback.setValidator(new LDAPPlainTextPasswordValidator());}} else {throw new UnsupportedCallbackException(callback);}}/*** Digest Validator.* This code is directly from the sun class, I was just curious how it worked.*/private class CustomDigestPasswordValidator implements PasswordValidationCallback.PasswordValidator {public boolean validate(final PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException {final PasswordValidationCallback.DigestPasswordRequest req = (PasswordValidationCallback.DigestPasswordRequest) request;final String passwd = req.getPassword();final String nonce = req.getNonce();final String created = req.getCreated();final String passwordDigest = req.getDigest();final String username = req.getUsername();if (null == passwd)return false;byte[] decodedNonce = null;if (null != nonce) {try {decodedNonce = Base64.decode(nonce);} catch (final Base64DecodingException bde) {throw new PasswordValidationCallback.PasswordValidationException(bde);}}String utf8String = "";if (created != null) {utf8String += created;}utf8String += passwd;final byte[] utf8Bytes;try {utf8Bytes = utf8String.getBytes("utf-8");} catch (final UnsupportedEncodingException uee) {throw new PasswordValidationCallback.PasswordValidationException(uee);}final byte[] bytesToHash;if (decodedNonce != null) {bytesToHash = new byte[utf8Bytes.length + decodedNonce.length];for (int i = 0; i < decodedNonce.length; i++)bytesToHash[i] = decodedNonce[i];for (int i = decodedNonce.length;i < utf8Bytes.length + decodedNonce.length;i++)bytesToHash[i] = utf8Bytes[i - decodedNonce.length];} else {bytesToHash = utf8Bytes;}final byte[] hash;try {final MessageDigest sha = MessageDigest.getInstance("SHA-1");hash = sha.digest(bytesToHash);} catch (final Exception e) {throw new PasswordValidationCallback.PasswordValidationException("Password Digest could not be created" + e);}return (passwordDigest.equals(Base64.encode(hash)));}}/*** LDAP Plain Text validator.*/private class LDAPPlainTextPasswordValidator implementsPasswordValidationCallback.PasswordValidator {/*** Validate the callback against the injected LDAP server.* Probably a good idea to have a cache manager - ehcache /  hazelcast injected to cache authenticated users.** @param request the callback request* @return true if login successful* @throws PasswordValidationCallback.PasswordValidationException**/public boolean validate(final PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException {final PasswordValidationCallback.PlainTextPasswordRequest plainTextPasswordRequest =(PasswordValidationCallback.PlainTextPasswordRequest) request;final String username = plainTextPasswordRequest.getUsername();final Authentication authentication;final Authentication userPassAuth = new UsernamePasswordAuthenticationToken(username, plainTextPasswordRequest.getPassword());authentication = ldapAuthenticationManager.authenticate(userPassAuth);return authentication.isAuthenticated();}}/*** Assert users.** @throws Exception error*/public void afterPropertiesSet() throws Exception {Assert.notNull(users, "Users is required.");Assert.notNull(this.ldapAuthenticationManager, "A LDAP Authentication manager is required.");}/*** Sets the users to validate against. Property names are usernames, property values are passwords.** @param users the users*/public void setUsers(final Properties users) {this.users = users;}/*** The the authentication manager.** @param ldapAuthenticationManager the provider*/public void setLdapAuthenticationManager(final AuthenticationManager ldapAuthenticationManager) {this.ldapAuthenticationManager = ldapAuthenticationManager;}
}

服務配置:
端點,CallbackHandler和LDAP身份驗證管理器的配置。
應用程序上下文–服務器端:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:sws="http://www.springframework.org/schema/web-services"xmlns:s="http://www.springframework.org/schema/security"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/web-serviceshttp://www.springframework.org/schema/web-services/web-services-2.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-3.0.xsd"><sws:annotation-driven/><context:component-scan base-package="javaitzen.spring.ws"/><sws:dynamic-wsdl id="exampleService"portTypeName="javaitzen.spring.ws.ExampleServiceEndpoint"locationUri="/exampleService/"targetNamespace="http://www.briandupreez.net/exampleService"><sws:xsd location="classpath:/xsd/Example1Request.xsd"/><sws:xsd location="classpath:/xsd/Example1Response.xsd"/><sws:xsd location="classpath:/xsd/Example2Request.xsd"/><sws:xsd location="classpath:/xsd/Example2Response.xsd"/></sws:dynamic-wsdl><sws:interceptors><bean id="validatingInterceptor"class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor"><property name="schema" value="classpath:/xsd/Example1Request.xsd"/><property name="validateRequest" value="true"/><property name="validateResponse" value="true"/></bean><bean id="loggingInterceptor"class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/><bean class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor"><property name="policyConfiguration" value="/WEB-INF/securityPolicy.xml"/><property name="callbackHandlers"><list><ref bean="callbackHandler"/></list></property></bean></sws:interceptors><bean id="callbackHandler" class="javaitzen.spring.ws.CustomValidationCallbackHandler"><property name="ldapAuthenticationManager" ref="authManager" /></bean><s:authentication-manager alias="authManager"><s:ldap-authentication-provideruser-search-filter="(uid={0})"user-search-base="ou=users"group-role-attribute="cn"role-prefix="ROLE_"></s:ldap-authentication-provider></s:authentication-manager><!-- Example... (inmemory apache ldap service) --><s:ldap-server id="contextSource" root="o=example" ldif="classpath:example.ldif"/><!--If you want to connect to a real LDAP server it would look more like:<s:ldap-server  id="contextSource" url="ldap://localhost:7001/o=example" manager-dn="uid=admin,ou=system" manager-password="secret"></s:ldap-server>--><bean id="marshallingPayloadMethodProcessor"class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor"><constructor-arg ref="serviceMarshaller"/><constructor-arg ref="serviceMarshaller"/></bean><bean id="defaultMethodEndpointAdapter"class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter"><property name="methodArgumentResolvers"><list><ref bean="marshallingPayloadMethodProcessor"/></list></property><property name="methodReturnValueHandlers"><list><ref bean="marshallingPayloadMethodProcessor"/></list></property></bean><bean id="serviceMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>javaitzen.spring.ws.Example1</value><value>javaitzen.spring.ws.Example1Response</value><value>javaitzen.spring.ws.Example2</value><value>javaitzen.spring.ws.Example2Response</value></list></property><property name="marshallerProperties"><map><entry key="jaxb.formatted.output"><value type="java.lang.Boolean">true</value></entry></map></property></bean></beans>

安全上下文–服務器端:

xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config"><xwss:RequireTimestamp maxClockSkew="60" timestampFreshnessLimit="300"/><!-- Expect plain text tokens from the client --><xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/><xwss:Timestamp/><!-- server side reply token --><xwss:UsernameToken name="server" password="server1" digestPassword="false" useNonce="false"/>
</xwss:SecurityConfiguration>

Web XML:
這里沒有什么特別的,只是Spring WS MessageDispatcherServlet。

spring-wsorg.springframework.ws.transport.http.MessageDispatcherServlettransformWsdlLocationstrue1spring-ws/*

客戶端配置:
要測試或使用該服務,您需要:
應用程序上下文–客戶端測試:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/><bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"><constructor-arg ref="messageFactory"/><property name="marshaller" ref="serviceMarshaller"/><property name="unmarshaller" ref="serviceMarshaller"/><property name="defaultUri" value="http://localhost:7001/example/spring-ws/exampleService"/><property name="interceptors"><list><ref local="xwsSecurityInterceptor"/></list></property></bean><bean id="xwsSecurityInterceptor"class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor"><property name="policyConfiguration" value="testSecurityPolicy.xml"/><property name="callbackHandlers"><list><ref bean="callbackHandler"/></list></property></bean><!--  As a client the username and password generated by the server must match with the client! --><!-- a simple callback handler to configure users and passwords with an in-memory Properties object. --><bean id="callbackHandler"class="org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler"><property name="users"><props><prop key="server">server1</prop></props></property></bean><bean id="serviceMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>javaitzen.spring.ws.Example1</value><value>javaitzen.spring.ws.Example1Response</value><value>javaitzen.spring.ws.Example2</value><value>javaitzen.spring.ws.Example2Response</value></list></property><property name="marshallerProperties"><map><entry key="jaxb.formatted.output"><value type="java.lang.Boolean">true</value></entry></map></property></bean>

安全上下文–客戶端:

<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config"><xwss:RequireTimestamp maxClockSkew="60" timestampFreshnessLimit="300"/><!-- Expect a plain text reply from the server --><xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/><xwss:Timestamp/><!-- Client sending to server --><xwss:UsernameToken name="example" password="pass" digestPassword="false" useNonce="false"/>
</xwss:SecurityConfiguration>

與Java通常一樣,在jar和版本方面可能會有一些細微差別,因此下面是我使用的pom的一部分。
依賴關系:

3.0.6.RELEASE2.0.2.RELEASEorg.apache.directory.serverapacheds-all1.5.5jarcompileorg.springframework.wsspring-ws-core${spring-ws-version}org.springframeworkspring-webmvc${spring-version}org.springframeworkspring-web${spring-version}org.springframeworkspring-context${spring-version}org.springframeworkspring-core${spring-version}org.springframeworkspring-beans${spring-version}org.springframeworkspring-oxm${spring-version}org.springframework.wsspring-ws-security${spring-ws-version}org.springframework.securityspring-security-core${spring-version}org.springframework.securityspring-security-ldap${spring-version}org.springframework.ldapspring-ldap-core1.3.0.RELEASEorg.apache.ws.securitywss4j1.5.12com.sun.xml.wssxws-security3.0org.apache.ws.commons.schemaXmlSchema1.4.2</project>

參考: Spring 3,Spring Web Services 2和LDAP安全性。 來自我們的JCG合作伙伴 ? Zen博客中的Zen領域的 Brian Du Preez。


翻譯自: https://www.javacodegeeks.com/2012/02/spring-3-spring-web-services-2-ldap.html

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

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

相關文章

vue 日期選擇器默認時間_vue-datepicker

vue-datepicker基于 Vue 的日期/時間選擇組件。安裝NodeJS 環境 (commonjs)npm i hyjiacan/vue-datepicker或者yarn add hyjiacan/vue-datepicker可以通過以下方式獲取最新的代碼git clone https://github.com/hyjiacan/vue-datepicker.git源碼倉庫瀏覽器環境 (umd)Since 2.4.0…

easyUI validate函數【總結篇-部分轉】

以下是自己總結和修改別人的帖子和資源整理出來的一些常用驗證函數&#xff0c;備用&#xff0c;交流。 <body>郵箱驗證&#xff1a;<input type"text" validtype"email" required"true" missingMessage"不能為空" invalidMe…

CSDN挑戰編程——《金色十月線上編程比賽第一題:小女孩數數》

金色十月線上編程比賽第一題&#xff1a;小女孩數數 題目詳情: 【金色十月線上編程比賽規則】 一個小女孩正在用左手手指數數&#xff0c;從1數到n。她從拇指算作1開始數起&#xff0c;然后&#xff0c;食指為2&#xff0c;中指為3&#xff0c;無名指為4&#xff0c;小指為5。…

ubuntu 安裝完成后的工作

以安裝 ubuntu 15.10 為例 1. 備份并更改源 1 cd /etc/apt 2 sudo cp source.list source.list.bak 3 sudo vi source.list 刪除所有內容并增加其他源&#xff08;用vi刪除所有內容&#xff0c;命令行下gg移動光標至文件頭&#xff0c;dG刪除光標后所有內容&#xff09; 阿里云…

Morphia和MongoDB:不斷發展的文檔結構

在上一篇有關Morphia的文章中 &#xff0c;我介紹了一些典型用法&#xff0c;并提到了一些已知問題的警告和解決方法。 我展示了使用Morphia多么容易&#xff0c;以及它與Java世界的交互方式。 為了跟進該帖子&#xff0c;我將討論如何處理一些現實生活中的需求&#xff1a;處理…

angular 點菜_Vue2與Angular5實現無人點餐、無人收銀系統項目實戰視頻教程【組合套餐】(大地)...

Vue2實現無人點餐、無人收銀系統項目實戰視頻教程詳情地址&#xff1a;Angular5實現無人點餐、無人收銀系統項目實戰視頻教程詳情地址&#xff1a;教程介紹&#xff1a;Vue2與Angular5實現無人點餐、無人收銀系統項目實戰視頻教程【組合套餐】是由大地老師傾情錄制的最新Vue2與…

CSDN挑戰編程——《金色十月線上編程比賽第二題:解密》

金色十月線上編程比賽第二題&#xff1a;解密 題目詳情: 小強是一名學生&#xff0c; 同時他也是一個黑客。 考試結束后不久&#xff0c;他驚訝的發現自己的高等數學科目居然掛了&#xff0c;于是他果斷入侵了學校教務部網站。在入侵的過程中&#xff0c;他發現了與成績相關的…

iOS學習心得——UITableViewCell的復用

UITableView是在iOS開發中最常用的控件之一。我的第一篇學習心得獻給它了UITableView是由一行一行的UITableViewCell構成的。首先想這樣一個問題&#xff1a;現在用UITableView去做一個聯系人列表&#xff0c;如果我有10個100個聯系人&#xff0c;那我可以建10個100 個UITab…

Java EE 7的高峰–使用EclipseLink的多租戶示例

水族館是有關所有相關規范和參考實現中有關Java EE進度的靈感和最新信息的重要來源。 他們從Oracle的Shaun Smith&#xff08; 博客 / twitter &#xff09;獲得了關于EclipseLink作為開源項目的地位和未來的演講。 他介紹了將在EclipseLink 2.4中提供的所有新功能&#xff0c;…

vscode中如何拉取git代碼_使用VSCode如何從github拉取項目的實現

使用VSCode如何從github拉取項目的實現最近使用vscode進行前端編程&#xff0c;遇到一些問題網上說明的不是很明顯&#xff0c;故記錄一下1.開vscode使用CTRL或者點擊查看到集成終端打開控制終端到此這篇關于使用VSCode如何從github拉取項目的實現的文章就介紹到這了,更多相關V…

matlab求導

在matlab中求導要進行符號運算。 >>syms x; >>y x^cos(x); >>ydot diff(y, x, 1);%對x求一階導數 ydot x^(cos(x) - 1)*cos(x) - x^cos(x)*log(x)*sin(x) >> y2dot diff(y, x, 2)%求二階導數&#xff0c;求n階導數同理。 y2dot cos(x)*(x…

帶有Java和Axis2的JSON Web服務

我最近遇到一位客戶&#xff0c;要求我使用Java Web服務重建其舊產品。 他們希望它模塊化并且易于使用。 我想到的第一件事是使用寧靜的方法。 但是讓我煩惱的是&#xff0c;Java寧靜的方法是使用XML !&#xff0c;我更喜歡一種更簡單的通信方式&#xff0c;易于理解和解析的數…

Kosaraju算法 有向圖的強連通分量

有向圖的強連通分量即&#xff0c;在有向圖G中&#xff0c;如果兩個頂點間至少存在一條路徑&#xff0c;稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通&#xff0c;稱G是一個強連通圖。非強連通圖有向圖的極大強連通子圖&#xff0c;稱為強連通分量(…

監管大屏系統_工廠大屏可視化管控系統,智慧工廠平臺是什么,工廠管理大屏軟件 - 帆軟...

智慧工廠大屏可視化管控系統&#xff0c;不但注重顯示數據顯示信息能力&#xff0c;還要兼具監管的作用&#xff0c;配合時代新興的大屏技術&#xff0c;早已成為精益生產工廠的必備產品。本文權威介紹智慧工廠大屏可視化管控系統是什么&#xff0c;以及3款主流軟件&#xff0c…

圖像二維離散傅里葉變換、幅度譜、相位譜

clear, clc I imread(...);F fftshift(fft2(I)); % 對圖像進行二維 DFT(fft2)&#xff0c;并移至中心位置 magn log(abs(F)); % 加 log 是便于顯示&#xff0c;縮小值域 phase log(angle(F)*180/pi); % 轉換為度數…

詳解CSS選擇器、優先級與匹配原理

選擇器種類 嚴格來講&#xff0c;選擇器的種類可以分為三種&#xff1a;標簽名選擇器、類選擇器和ID選擇器。而所謂的后代選擇器和群組選擇器只不過是對前三種選擇器的擴展應用。而在標簽內寫入style""的方式&#xff0c;應該是CSS的一種引入方式&#xff0c;而不是選…

關于299$的企業開發者賬號的申請流程

299$的企業開發者賬號 Apple Developer Enterprise Program?一年1988人民幣 - 企業 (Apple Developer Enterprise Program)- 公司應在鄧白氏注冊并擁有有效的 DUNS 號碼。&#xff0d;此計劃使開發者能夠開發針對 Apple 設備的應用程式&#xff0c;并對其員工進行發布&#xf…

keras 多層lstm_tensorflow-如何在keras中堆疊多個lstm?

DanielAdiwardana的答案的詳細說明。我們需要為除最后一層之外的所有LSTM層添加return_sequences True。將此標志設置為True可讓Keras知道LSTM輸出應包含所有歷史生成的輸出以及時間戳(3D)。 因此&#xff0c;下一個LSTM層可以進一步處理數據。如果此標志為假&#xff0c;則LS…

Java堆空間– JRockit和IBM VM

本文將為您提供JRockit Java堆空間與HotSpot VM的概述。 它還將為您提供有關JRockit和HotSpot的Oracle未來計劃的一些背景知識。 Oracle JRockit VM Java堆&#xff1a;2個不同的內存空間 -Java堆&#xff08;YoungGen和OldGen&#xff09; -本機內存空間&#xff08;類池&am…

如何搭建lamp(CentOS7+Apache+MySQL+PHP)環境 [轉]

在網上搜資料,自己在本地虛擬機上嘗試搭建,弄了整整一天一夜,終于弄好了.網上的資料,雖然很多,但大多都是重復的,拿去試了之后,又很多都不能得到正確的結果.最終找到了適合我的linux環境的搭建方式;在這里貼出來:Install Apache, PHP And MySQL On CentOS 7 (LAMP)度娘真不給力…