• WCF安全之customBinding


    本文是关于WCF安全的一个完整示例,WCF宿主选用IIS,并通过添加“启用Silverlight功能的WCF服务”的方式建立WCF服务。

    WCF服务的绑定方式采用Visual Studio 2008默认的customBinding,安全模式选用Transport安全模式(httpsTransport),身份验证模式则选用UserNameOverTransport。

    本示例的客户端为Silverlight,并在访问WCF服务时使用了Visual Studio 2008自动生成的代理类。

    测试用服务类:

    using System;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.Collections.Generic;
    using System.Text;
    
    namespace SecSample.Web
    {
        [ServiceContract(Namespace = "")]
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
        public class WeatherService
        {
            [OperationContract]
            public string GetWeather()
            {
                return "Sunny";
            }
        }
    }

    1、配置IIS

    1.1 生成证书

    可以使用Makecert.exe工具生成一个测试用的证书,命令如下:

    makecert -sr localmachine -ss My -n CN=localhost -sky exchange -pe -r

    其中cn=localhost,表示证书的名称为localhost。

    本环节需要注意的问题是:

    a. 证书名称必须与访问WCF服务所用的域名或机器名一致,否则用IE访问时会出现如下警告

    image

    用WCF客户端访问时则会导致“无法为 SSL/TLS 安全通道与颁发机构“XXXX”建立信任关系。”的错误。

    该限制的直接后果就是造成无法通过不同域名或IP地址访问同一个网站(比如用localhost或192.168.1.8访问本机),暂未找到生成多域名证书的方法,正在郁闷中,如有高手知道解决措施,望不吝赐教。

    b. 以上命令行生成的证书存储在“个人”证书中,需要导入到“受信任的根证书颁发机构”或“受信任的发布者”中。

    1.2 为IIS配置绑定

    编辑网站绑定,添加https类型,并指定SSL证书。如下图:

    image

    2、服务端配置

    Web.config文件中system.serviceModel节的代码如下:

      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior name="defaultServiceBehavior">
              <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
              <serviceCredentials>
                <userNameAuthentication userNamePasswordValidationMode="Custom"
                  customUserNamePasswordValidatorType="SecSample.Web.CustomUserNameValidator,SecSample.Web" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <bindings>
          <customBinding>
            <binding name="defaultCustomBinding">
              <binaryMessageEncoding />
              <security authenticationMode="UserNameOverTransport"/>
              <httpsTransport/>
            </binding>
          </customBinding>
        </bindings>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <services>
          <service behaviorConfiguration="defaultServiceBehavior" name="SecSample.Web.WeatherService">
            <endpoint address="" binding="customBinding" bindingConfiguration="defaultCustomBinding"
              contract="SecSample.Web.WeatherService" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          </service>
        </services>
      </system.serviceModel>

    serviceBehaviors节中命名为defaultServiceBehavior的behavior设置了如下内容:

    a. 允许https协议获取元数据

    b. userNamePasswordValidationMode选用Custom,验证类为继承自UserNamePasswordValidator类的CustomUserNameValidator类,CustomUserNameValidator类的完整源代码如下:

    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Selectors;
    using System.Linq;
    using System.ServiceModel;
    using System.Web;
    
    namespace SecSample.Web
    {
        public class CustomUserNameValidator : UserNamePasswordValidator
        {
    
            public override void Validate(string userName, string password)
            {
                if (userName == "admin" && password == "123456") return;
                throw new ApplicationException("验证失败!");
            }
        }
    }

    customBinding节中命名为defaultCustomBinding的binding设置了customBinding所选用的编码方式(binaryMessageEncoding)、安全验证模式(UserNameOverTransport)及传输协议(httpsTransport)。

    3、客户端配置

    客户端ServiceReferences.ClientConfig文件的完整代码如下:

    <configuration>
      <system.serviceModel>
        <bindings>
          <customBinding>
            <binding name="defaultCustomBinding">
              <binaryMessageEncoding />
              <security authenticationMode="UserNameOverTransport" />
              <httpsTransport />
            </binding>
          </customBinding>
        </bindings>
        <client>
          <endpoint address="../WeatherService.svc" binding="customBinding"
            bindingConfiguration="defaultCustomBinding" contract="WeatherServiceRef.WeatherService"
            name="CustomBinding_WeatherService" />
        </client>
      </system.serviceModel>
    </configuration>

    由于Silverlight及WCF使用同一个网站承载并假定相对位置固定,客户端终结点使用了相对地址“../WeatherService.svc”

    以避免更换域名造成的问题(可惜证书与域名绑定的问题避免不了),customBinding节中则作了与服务器端对应的配置。

    4、客户端示例页面

    MainPage.xaml文件:

    <UserControl x:Class="SecSample.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
      <Grid x:Name="LayoutRoot">
            <Button Name="btnGet" Content="GetWeather" Click="GetWeather"
                    HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
      </Grid>
    </UserControl>

    MainPage.xaml.cs文件:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using SecSample.WeatherServiceRef;
    
    namespace SecSample
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
    
                _client = new SecSample.WeatherServiceRef.WeatherServiceClient();
    
                _client.ClientCredentials.UserName.UserName = "admin";
                _client.ClientCredentials.UserName.Password = "123456";
    
                 
                _client.GetWeatherCompleted += new EventHandler<GetWeatherCompletedEventArgs>(_client_GetWeatherCompleted);
            }
            
            private WeatherServiceClient _client;
    
            private void GetWeather(object sender, RoutedEventArgs e)
            {
                this._client.GetWeatherAsync();
                this.btnGet.IsEnabled = false;
            }
    
            void _client_GetWeatherCompleted(object sender, GetWeatherCompletedEventArgs e)
            {
                this.btnGet.IsEnabled = true;
                
                if (e.Error == null)
                {
                    MessageBox.Show(e.Result);
                }
                else
                {
                    MessageBox.Show(e.Error.Message);
                }
            }
        }
    }

    示例页面非常简单,添加一个按钮并在按钮单击时调用WCF服务,调用成功时显示调用结果,否则显示错误信息。

    需注意的是客户端代理类的初始化,在服务器端要求UserNameOverTransport验证后,需要为客户端代理类指定UserName及Password。

    至此,整个示例就完成了。运行效果图如下:

    image

    但如果用另一个机器访问该服务,会可能会出现如下警告:

    image

    这是由于我们使用的只是自己生成的测试用证书,而该证书并没有受到客户机的信任。如果只是测试或企业内部使用,客户端将该证书安装到受信任区域即可,如果是正式对外提供服务,则可能需要向相关机构申请正式证书。

    示例测试环境:

    操作系统:Windows7

    开发环境:Visual Studio 2008 + Silverlight 3

    IIS:7.5

    浏览器:IE8

  • 相关阅读:
    ELK 收集 K8S (containerd 容器运行时) 二
    EFK 收集 Docker 日志
    ELK 收集 Docker 日志
    ELK 收集 K8S (containerd 容器运行时) 三
    Java 基础(Stream APl)
    Java 基础(方法引用 Method References)
    Java 基础(Lambda表达式 和 函数式 Functional 接口)
    Java 基础(Stream APl) 二
    ELK 收集 K8S (containerd 容器运行时) 一
    部署 Harbor 2.4.1
  • 原文地址:https://www.cnblogs.com/chinadhf/p/1723203.html
Copyright © 2020-2023  润新知