关于WEB Service&WCF&WebApi实现身份验证之WCF篇(1)

简介:

WCF身份验证一般常见的方式有:自定义用户名及密码验证、X509证书验证、ASP.NET成员资格(membership)验证、SOAP Header验证、Windows集成验证、WCF身份验证服务(AuthenticationService),这些验证方式其实网上都有相关的介绍文章,我这里算是一个总结吧,顺便对于一些注意细节进行说明,以便大家能更好的掌握这些知识。

第一种:自定义用户名及密码验证(需要借助X509证书)

由于该验证需要借助于X509证书,所以我们需要先创建一个证书,可以利用MS自带的makecert.exe程序来制作测试用证书,使用步骤:请依次打开开始->Microsoft Visual Studio 2010(VS菜单,版本不同,名称有所不同)->Visual Studio Tools->Visual Studio 命令提示,然后执行以下命令:

makecert -r -pe -n "CN=ZwjCert" -ss TrustedPeople -sr LocalMachine -sky exchange

上述命令中除了我标粗的部份可改成你实际的请求外(为证书名称),其余的均可以保持不变,命令的意思是:创建一个名为ZwjCert的证书将将其加入到本地计算机的受信任人区域中。

如果需要查看该证书,那么可以通过MMC控制台查询证书,具体操作步骤如下:

运行->MMC,第一次打开Windows没有给我们准备好直接的管理证书的入口,需要自行添加,添加方法如下:

1. 在控制台菜单,文件→添加/删除管理单元→添加按钮→选”证书”→添加→选”我的用户账户”→关闭→确定
2. 在控制台菜单,文件→添加/删除管理单元→添加按钮→选”证书”→添加→选”计算机账户”→关闭→确定

这样MMC中左边就有菜单了,然后依次展开:证书(本地计算机)->受信任人->证书,最后就可以在右边的证书列表中看到自己的证书了,如下图示:

 

证书创建好,我们就可以开始编码了,本文主要讲的就是WCF,所以我们首先定义一个WCF服务契约及服务实现类(后面的各种验证均采用该WCF服务),我这里直接采用默认的代码,如下:

要实现用户名及密码验证,就需要定义一个继承自UserNamePasswordValidator的用户名及密码验证器类CustomUserNameValidator,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace  WcfAuthentications
{
     public  class  CustomUserNameValidator : UserNamePasswordValidator
     {
 
         public  override  void  Validate( string  userName,  string  password)
         {
             if  ( null  == userName ||  null  == password)
             {
                 throw  new  ArgumentNullException();
             }
             if  (userName !=  "admin"  && password !=  "wcf.admin" //这里可依实际情况下实现用户名及密码判断
             {
                 throw  new  System.IdentityModel.Tokens.SecurityTokenException( "Unknown Username or Password" );
             }
 
         }
     }
}

代码很简单,只是重写其Validate方法,下面就是将创建WCF宿主,我这里采用控制台程序

代码部份:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace  WcfHost
{
     class  Program
     {
         static  void  Main( string [] args)
         {
             using  ( var  host =  new  ServiceHost( typeof (Service1)))
             {
                 host.Opened +=  delegate
                 {
                     Console.WriteLine( "Service1 Host已开启!" );
                 };
                 host.Open();
                 Console.ReadKey();
             }
         }
     }
}

APP.CONFIG部份(这是重点,可以使用WCF配置工具来进行可视化操作配置,参见:http://www.cnblogs.com/Moosdau/archive/2011/04/17/2019002.html):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
< system.serviceModel >
   < bindings >
     < wsHttpBinding >
       < binding  name="Service1Binding">
         < security  mode="Message">
           < message  clientCredentialType="UserName" />
         </ security >
       </ binding >
     </ wsHttpBinding >
   </ bindings >
   < services >
     < service  behaviorConfiguration="Service1Behavior" name="WcfAuthentications.Service1">
       < endpoint  address="" binding="wsHttpBinding" bindingConfiguration="Service1Binding"
         contract="WcfAuthentications.IService1">
         < identity >
           < dns  value="ZwjCert" />
         </ identity >
       </ endpoint >
       < endpoint  address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
       < host >
         < baseAddresses >
           < add  baseAddress="http://localhost:8732/WcfAuthentications/Service1/" />
         </ baseAddresses >
       </ host >
     </ service >
   </ services >
   < behaviors >
     < serviceBehaviors >
       < behavior  name="Service1Behavior">
         < serviceMetadata  httpGetEnabled="true" />
         < serviceDebug  includeExceptionDetailInFaults="false" />
         < serviceCredentials >
           < serviceCertificate  findValue="ZwjCert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="TrustedPeople" />
           < userNameAuthentication  userNamePasswordValidationMode="Custom"
             customUserNamePasswordValidatorType="WcfAuthentications.CustomUserNameValidator,WcfAuthentications" />
         </ serviceCredentials >
       </ behavior >
     </ serviceBehaviors >
   </ behaviors >
</ system.serviceModel >

这里面有几个需要注意的点:

1.<dns value="ZwjCert" />与<serviceCertificate findValue="ZwjCert" ..>中的value必需都为证书的名称,即:ZwjCert;

2.Binding节点中需配置security节点,message子节点中的clientCredentialType必需设为:UserName;

3.serviceBehavior节点中,需配置serviceCredentials子节点,其中serviceCertificate 中各属性均需与证书相匹配,userNameAuthentication的userNamePasswordValidationMode必需为Custom,customUserNamePasswordValidatorType为上面自定义的用户名及密码验证器类的类型及其程序集

最后就是在客户端使用了,先引用服务,然后看下App.Config,并进行适当的修改,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
< system.serviceModel >
     < bindings >
         < wsHttpBinding >
             < binding  name="WSHttpBinding_IService1" >
                 < security  mode="Message">
                     < transport  clientCredentialType="Windows" proxyCredentialType="None"
                         realm="" />
                     < message  clientCredentialType="UserName" negotiateServiceCredential="true"
                         algorithmSuite="Default" />
                 </ security >
             </ binding >
         </ wsHttpBinding >
     </ bindings >
     < client >
         < endpoint  address="http://localhost:8732/WcfAuthentications/Service1/"
             binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
             contract="ServiceReference1.IService1" name="WSHttpBinding_IService1">
             < identity >
                 < dns  value="ZwjCert" />
             </ identity >
         </ endpoint >
     </ client >
</ system.serviceModel >

为了突出重点,我这里对Binding节点进行了精简,去掉了许多的属性配置,仅保留重要的部份,如:security节点,修改其endpoint下面的identity中<dns value="ZwjCert" />,这里的value与服务中所说的相同节点相同,就是证书名称,如果不相同,那么就会报错,具体的错误消息大家可以自行试下,我这里限于篇幅内容就不贴出来了。

客户端使用服务代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
namespace  WCFClient
{
     class  Program
     {
         static  void  Main( string [] args)
         {
             using  ( var  proxy =  new  ServiceReference1.Service1Client())
             {
                 proxy.ClientCredentials.UserName.UserName =  "admin" ;
                 proxy.ClientCredentials.UserName.Password =  "wcf.admin" ;
                 string  result = proxy.GetData(1);
                 Console.WriteLine(result);
                 var  compositeObj = proxy.GetDataUsingDataContract( new  CompositeType() { BoolValue =  true , StringValue =  "test"  });
                 Console.WriteLine(SerializerToJson(compositeObj));
             }
             Console.ReadKey();
         }
 
         /// <summary>
         /// 序列化成JSON字符串
         /// </summary>
         static  string  SerializerToJson<T>(T obj)  where  T: class
         {
             var  serializer =  new  DataContractJsonSerializer( typeof (T));
             var  stream =  new  MemoryStream();
             serializer.WriteObject(stream,obj);
 
             byte [] dataBytes =  new  byte [stream.Length];
 
             stream.Position = 0;
             stream.Read(dataBytes, 0, ( int )stream.Length);
             string  dataString = Encoding.UTF8.GetString(dataBytes);
             return  dataString;
         }
     }
}

运行结果如下图示:

  

如果不传入用户名及密码或传入不正确的用户名及密码,均会报错:

第二种:X509证书验证


首先创建一个证书,我这里就用上面创建的一个证书:ZwjCert;由于服务器端及客户端均需要用到该证书,所以需要导出证书,在客户端的电脑上导入该证书,以便WCF可进行验证。

WCF服务契约及服务实现类与第一种方法相同,不再重贴代码。

WCF服务器配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
< system.serviceModel >
   < bindings >
     < wsHttpBinding >
       < binding  name="Service1Binding">
         < security  mode="Message">
           < message  clientCredentialType="Certificate" />
         </ security >
       </ binding >
     </ wsHttpBinding >
   </ bindings >
   < services >
     < service  behaviorConfiguration="Service1Behavior" name="WcfAuthentications.Service1">
       < endpoint  address="" binding="wsHttpBinding" bindingConfiguration="Service1Binding"
         contract="WcfAuthentications.IService1">
       </ endpoint >
       < endpoint  address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
       < host >
         < baseAddresses >
           < add  baseAddress="http://127.0.0.1:8732/WcfAuthentications/Service1/" />
         </ baseAddresses >
       </ host >
     </ service >
   </ services >
   < behaviors >
     < serviceBehaviors >
       < behavior  name="Service1Behavior">
         < serviceMetadata  httpGetEnabled="true" />
         < serviceDebug  includeExceptionDetailInFaults="false" />
         < serviceCredentials >
           < serviceCertificate  findValue="ZwjCert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="TrustedPeople" />
           < clientCertificate >
             < authentication  certificateValidationMode="None"/>
           </ clientCertificate >
         </ serviceCredentials >
       </ behavior >
     </ serviceBehaviors >
   </ behaviors >
</ system.serviceModel >

这里需注意如下几点:

1.<message clientCredentialType="Certificate" />clientCredentialType设为:Certificate;

2.需配置serviceCredentials节点,其中serviceCertificate 中各属性均需与证书相匹配,clientCertificate里面我将authentication.certificateValidationMode="None",不设置采用默认值其实也可以;

客户端引用服务,自动生成如下配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
< system.serviceModel >
     < bindings >
         < wsHttpBinding >
             < binding  name="WSHttpBinding_IService1">
                 < security  mode="Message">
                     < transport  clientCredentialType="Windows" proxyCredentialType="None"
                         realm="" />
                     < message  clientCredentialType="Certificate" negotiateServiceCredential="true"
                         algorithmSuite="Default" />
                 </ security >
             </ binding >
         </ wsHttpBinding >
     </ bindings >
     < client >
         < endpoint  address="http://127.0.0.1:8732/WcfAuthentications/Service1/"
             binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
             contract="ServiceReference1.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="Service1Nehavior">
             < identity >
                 < certificate  encodedValue="AwAAAAEAAAAUAAAAkk2avjNCItzUlS2+Xj66ZA2HBZYgAAAAAQAAAOwBAAAwggHoMIIBVaADAgECAhAIAOzFvLxLuUhHJRwHUUh9MAkGBSsOAwIdBQAwEjEQMA4GA1UEAxMHWndqQ2VydDAeFw0xNTEyMDUwMjUyMTRaFw0zOTEyMzEyMzU5NTlaMBIxEDAOBgNVBAMTB1p3akNlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALfGfsiYpIVKu3gPJl790L13+CZWt6doePZHmcjMl+xPQKIR2fDvsCq9ZxzapDgiG4T3mgcVKUv55DBiuHcpXDvXt28m49AjdKwp924bOGKPM56eweKDCzYfLxy5SxaZfA9qjUhnPq3kGu1lfWjXbsp1rKI1UhKJg5b2j0V7AOC3AgMBAAGjRzBFMEMGA1UdAQQ8MDqAEH/MEXV8FHNLtxvllQ5SMbihFDASMRAwDgYDVQQDEwdad2pDZXJ0ghAIAOzFvLxLuUhHJRwHUUh9MAkGBSsOAwIdBQADgYEAdBtBNTK/Aj3woH2ts6FIU3nh7FB2tKQ9L3k6QVL+kCR9mHuqWtYFJTBKxzESN2t0If6muiktcO+C8iNwYpJpPzLAOMFMrTQhkO82gcdr9brQzMWPTraK1IS+GGH8QBIOTLx9zfV/iCIXxRub+Sq9dmRSQjKDeLeHWoE5I6FkQJg=" />
             </ identity >
         </ endpoint >
     </ client >
   < behaviors >
     < endpointBehaviors >
       < behavior  name="Service1Nehavior">
         < clientCredentials >
           < clientCertificate  findValue="ZwjCert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="TrustedPeople" />
         </ clientCredentials >
       </ behavior >
     </ endpointBehaviors >
   </ behaviors >
</ system.serviceModel >

可以看出endpoint节点下的identity.certificate的encodedValue包含了加密的数据,另外需要手动增加clientCertificate配置信息,该信息表示证书在本地电脑存放的位置,当然也可以通过代码来动态指定,如:proxy.ClientCredentials.ClientCertificate.SetCertificate("ZwjCert", StoreLocation.LocalMachine, StoreName.My);

客户端使用服务代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
static  void  Main( string [] args)
{
     using  ( var  proxy =  new  ServiceReference1.Service1Client())
     {
 
         //proxy.ClientCredentials.ClientCertificate.SetCertificate("ZwjCert", StoreLocation.LocalMachine, StoreName.My); //直接动态指定证书存储位置
         string  result = proxy.GetData(1);
         Console.WriteLine(result);
         var  compositeObj = proxy.GetDataUsingDataContract( new  CompositeType() { BoolValue =  true , StringValue =  "test"  });
         Console.WriteLine(SerializerToJson(compositeObj));
     }
     Console.ReadKey();
}

网上还有另类的针对X509证书验证,主要是采用了自定义的证书验证器类,有兴趣的可以参见这篇文章:http://www.cnblogs.com/ejiyuan/archive/2010/05/31/1748363.html

第三种:ASP.NET成员资格(membership)验证

 由于该验证需要借助于X509证书,所以仍然需要创建一个证书(方法如第一种中创建证书方法相同):ZwjCert;

由于该种验证方法是基于ASP.NET的membership,所以需要创建相应的数据库及创建账号,创建数据库,请通过运行aspnet_regsql.exe向导来创建数据库及其相关的表,通过打开ASP.NET 网站管理工具(是一个自带的管理网站),并在上面创建角色及用户,用于后续的验证;

这里特别说明一下,若采用VS2013,VS上是没有自带的GUI按钮来启动该管理工具网站,需要通过如下命令来动态编译该网站:

1
2
cd  C:\Program Files\IIS Express
iisexpress.exe  /path :C:\Windows\Microsoft.NET\Framework\v4.0.30319\ASP.NETWebAdminFiles  /vpath : /WebAdmin  /port :12345  /clr :4.0  /ntlm

编译时若出现报错:“System.Configuration.StringUtil”不可访问,因为它受保护级别限制,请将WebAdminPage.cs中代码作如下修改:

1
2
3
4
5
6
7
8
//取消部份:
string  appId = StringUtil.GetNonRandomizedHashCode(String.Concat(appPath, appPhysPath)).ToString( "x" , CultureInfo.InvariantCulture);
 
 
//新增加部份:
Assembly sysConfig = Assembly.LoadFile( @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Configuration.dll" );
Type sysConfigType = sysConfig.GetType( "System.Configuration.StringUtil" );
string  appId = (( int )sysConfigType.GetMethod( "GetNonRandomizedHashCode" ).Invoke( null new  object [] { String.Concat(appPath, appPhysPath),  true  })).ToString( "x" , CultureInfo.InvariantCulture);

这样就可以按照命令生生成的网址进行访问就可以了。如果像我一样,操作系统为:WINDOWS 10,那么不好意思,生成的网站虽然能够打开,但仍会报错:

遇到错误。请返回上一页并重试。

目前没有找到解决方案,网上有说ASP.NET网站管理工具在WIN10下不被支持,到底为何暂时无解,若大家有知道的还请分享一下(CSDN有别人的求问贴:http://bbs.csdn.net/topics/391819719),非常感谢,我这里就只好换台电脑来运行ASP.NET管理工具网站了。

 WCF服务端配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
< connectionStrings >
   < add  name="SqlConn" connectionString="Server=.;Database=aspnetdb;Uid=sa;Pwd=www.zuowenjun.cn;"/>
</ connectionStrings >
< system.web >
   < compilation  debug="true" targetFramework="4.5" />
   < httpRuntime  targetFramework="4.5"/>
   < membership  defaultProvider="SqlMembershipProvider">
     < providers >
       < clear />
       < add  name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SqlConn" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed"/>
     </ providers >
   </ membership >
</ system.web >
< system.serviceModel >
   < behaviors >
     < serviceBehaviors >
       < behavior  name="Service1Behavior">
         < serviceCredentials >
           < serviceCertificate  findValue="ZwjCert" storeLocation="LocalMachine"
             storeName="TrustedPeople" x509FindType="FindBySubjectName" />
           < userNameAuthentication  userNamePasswordValidationMode="MembershipProvider"
             membershipProviderName="SqlMembershipProvider" />
         </ serviceCredentials >
          < serviceMetadata  httpGetEnabled="true" httpsGetEnabled="true" />
         < serviceDebug  includeExceptionDetailInFaults="false" />
       </ behavior >
     </ serviceBehaviors >
   </ behaviors >
   < bindings >
     < wsHttpBinding >
       < binding  name="Service1Binding">
         < security  mode="Message">
           < message  clientCredentialType="UserName"/>
         </ security >
       </ binding >
     </ wsHttpBinding >
   </ bindings >
   < serviceHostingEnvironment  aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
< services >
   < service  name="WcfService1.Service1" behaviorConfiguration="Service1Behavior">
     < endpoint  address="" binding="wsHttpBinding" contract="WcfService1.IService1" bindingConfiguration="Service1Binding">
     </ endpoint >
   </ service >
</ services >
</ system.serviceModel >

这里需注意几点:

1.配置connectionString,连接到membership所需的数据库; 

2.配置membership,增加SqlMembershipProvider属性配置;

3.配置serviceCredential,与第一种基本相同,不同的是userNameAuthentication的配置:userNamePasswordValidationMode="MembershipProvider",membershipProviderName="SqlMembershipProvider";

4.配置Binding节点<message clientCredentialType="UserName"/>,这与第一种相同; 

客户端引用WCF服务,查看生成的配置文件内容,需确保Binding节点有以下配置信息:

1
2
3
< security  mode="Message">
         < message  clientCredentialType="UserName" />
  </ security >

最后使用WCF服务,使用代码与第一种相同,唯一需要注意的是,传入的UserName和Password均为ASP.NET网站管理工具中创建的用户信息。

另外我们也可以采用membership+Form验证,利用ASP.NET的身份验证机制,要实现这种模式,是需要采用svc文件,并寄宿在IIS上,具体实现方法,参见:http://www.cnblogs.com/danielWise/archive/2011/01/30/1947912.html

由于WCF的验证方法很多,本文无法一次性全部写完,敬请期待续篇!

本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/5021270.html  ,如需转载请自行联系原作者

相关文章
|
1月前
|
存储 JSON 安全
如何使用 JSON Web Tokens 进行身份验证?
总的来说,JWT 是一种强大而灵活的身份验证方式,通过正确使用和管理,可以为应用提供可靠的身份验证机制,同时提高系统的可扩展性和安全性。在实际应用中,需要根据具体的需求和场景,合理设计和实施 JWT 身份验证方案。
111 63
|
4月前
【Azure 应用服务】Web App Service 中的 应用程序配置(Application Setting) 怎么获取key vault中的值
【Azure 应用服务】Web App Service 中的 应用程序配置(Application Setting) 怎么获取key vault中的值
|
1月前
【Azure App Service】PowerShell脚本批量添加IP地址到Web App允许访问IP列表中
Web App取消公网访问后,只允许特定IP能访问Web App。需要写一下段PowerShell脚本,批量添加IP到Web App的允许访问IP列表里!
|
4月前
|
存储 JSON 数据安全/隐私保护
"FastAPI身份验证与授权的奥秘:如何用Python打造坚不可摧的Web应用,让你的项目一鸣惊人?"
【8月更文挑战第31天】在现代Web开发中,保证应用安全性至关重要,FastAPI作为高性能Python框架,提供了多种身份验证与授权方式,包括HTTP基础认证、OAuth2及JWT。本文将对比这些机制并附上示例代码,展示如何使用HTTP基础认证、OAuth2协议以及JWT进行用户身份验证,确保只有合法用户才能访问受保护资源。通过具体示例,读者可以了解如何在FastAPI项目中实施这些安全措施。
180 1
|
4月前
|
关系型数据库 MySQL Linux
【Azure 应用服务】在创建Web App Service的时候,选Linux系统后无法使用Mysql in App
【Azure 应用服务】在创建Web App Service的时候,选Linux系统后无法使用Mysql in App
【Azure 应用服务】在创建Web App Service的时候,选Linux系统后无法使用Mysql in App
|
4月前
|
JavaScript 安全 前端开发
Node.js身份验证全攻略:策略与实践,打造坚不可摧的Web应用安全防线!
【8月更文挑战第22天】Node.js作为强大的服务器端JavaScript平台,对于构建高效网络应用至关重要。本文探讨其身份验证策略,涵盖从基于token至复杂的OAuth 2.0及JWT。Passport.js作为认证中间件,支持本地账号验证及第三方服务如Google、Facebook登录。同时介绍JWT轻量级验证机制,确保数据安全传输。开发者可根据应用需求选择合适方案,注重安全性以保护用户数据。
89 1
|
4月前
|
存储 安全 测试技术
Web2py中的身份验证与授权之谜:如何让你的Web应用飞起来?
【8月更文挑战第31天】在Web开发中,确保应用安全性至关重要,Web2py作为Python Web框架,提供了强大的身份验证与授权功能。本文探讨了Web2py的身份验证(包括表单验证、密码加密及会话管理)与授权(涵盖角色权限、URL过滤及用户组管理)。通过示例代码展示了用户模型定义、角色关系设置及登录流程处理等关键步骤。合理利用这些功能并结合最佳实践如使用内置验证、灵活控制访问权限及编写测试,可帮助开发者高效构建安全稳定的应用程序。
26 0
|
4月前
|
Shell PHP Windows
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
|
4月前
|
Linux 应用服务中间件 网络安全
【Azure 应用服务】查看App Service for Linux上部署PHP 7.4 和 8.0时,所使用的WEB服务器是什么?
【Azure 应用服务】查看App Service for Linux上部署PHP 7.4 和 8.0时,所使用的WEB服务器是什么?
|
4月前
【Azure 应用服务】通过 Web.config 开启 dotnet 应用的 stdoutLog 日志,查看App Service 产生500错误的原因
【Azure 应用服务】通过 Web.config 开启 dotnet 应用的 stdoutLog 日志,查看App Service 产生500错误的原因