次の方法で共有


チュートリアル: カスタム クライアントおよびサービスの資格情報を作成する

このトピックでは、クライアントおよびサービスにカスタム資格情報を実装する方法と、これをアプリケーション コードから使用する方法について説明します。

資格情報拡張クラス

ClientCredentials クラスおよび ServiceCredentials クラスは、Windows Communication Foundation (WCF) セキュリティ拡張のメイン エントリ ポイントです。 これらの資格情報クラスでは、アプリケーション コードから資格情報を設定し、資格情報の種類をセキュリティ トークンに変換する API を提供します ("セキュリティ トークン" とは、SOAP メッセージ内の資格情報を送信するために使用される形式です)。これらの資格情報クラスの役割は、次の 2 つの領域に分けることができます。

  • アプリケーションで資格情報を設定するための API を提供します。

  • SecurityTokenManager 実装のファクトリとして動作します。

WCF で提供される既定の実装では、システム指定の資格情報の種類をサポートし、これらの資格情報の種類を処理できるセキュリティ トークン マネージャーを作成します。

カスタマイズする理由

クライアントまたはサービスの資格情報クラスをカスタマイズする場合、いくつかの理由があります。 最大の理由として、システム指定の資格情報の種類の処理について、特に以下の必要性が生じたために WCF の既定のセキュリティ動作を変更する必要があることが挙げられます。

  • 他の拡張ポイントを使用した場合には不可能な変更

  • 新しい資格情報の種類の追加

  • 新しいカスタム セキュリティ トークンの種類の追加

このトピックでは、カスタムのクライアント資格情報およびサービス資格情報を実装する方法と、これをアプリケーション コードから使用する方法について説明します。

最初の手順

カスタム資格情報クラスを作成することは、最初の手順にすぎません。なぜなら、資格情報のプロビジョニング、セキュリティ トークンのシリアル化、または認証に関する WCF の動作を変更することが、資格情報をカスタマイズする理由だからです。 このセクションの他のトピックでは、カスタムのシリアライザーと認証システムを作成する方法について説明します。 カスタム資格情報クラスの作成は、このような観点からすると、一連のトピックの最初の手順になります。 これに続く処理 (カスタムのシリアライザーおよび認証システムの作成) は、カスタム資格情報の作成後にのみ可能になります。 このトピックに基づく他のトピックには、次のものがあります。

手順

カスタム クライアント資格情報を実装するには

  1. ClientCredentials クラスから派生する新しいクラスを定義します。

  2. 任意。 新しい資格情報の種類に新しいメソッドまたはプロパティを追加します。 新しい資格情報の種類を追加しない場合は、この手順を省略します。 次の例では、CreditCardNumber プロパティを追加します。

  3. CreateSecurityTokenManager メソッドをオーバーライドします。 カスタム クライアント資格情報が使用されると、WCF セキュリティ インフラストラクチャによってこのメソッドが自動的に呼び出されます。 このメソッドは、SecurityTokenManager クラスの実装のインスタンスを作成して返す役割を担います。

    重要

    カスタム セキュリティ トークン マネージャーを作成するために、CreateSecurityTokenManager メソッドがオーバーライドされることに注意する必要があります。 ClientCredentialsSecurityTokenManager から派生したセキュリティ トークン マネージャーは、実際のセキュリティ トークンを作成するために、SecurityTokenProvider から派生したカスタム セキュリティ トークン プロバイダーを返す必要があります。 このパターンに従ってセキュリティ トークンを作成しないと、ChannelFactory オブジェクトがキャッシュされたとき (これは、WCF クライアント プロキシの既定の動作です)、権限の昇格攻撃を受ける可能性があり、アプリケーションが正常に機能しない場合があります。 カスタム資格情報オブジェクトは、ChannelFactory の一部としてキャッシュされます。 ただし、カスタム SecurityTokenManager がすべての呼び出し時に作成され、これにより、トークン作成ロジックが SecurityTokenManager にある限り、セキュリティの脅威が軽減されます。

  4. CloneCore メソッドをオーバーライドします。

    public class MyClientCredentials : ClientCredentials
    {
        string creditCardNumber;
    
        public MyClientCredentials()
        {
            // Perform client credentials initialization.
        }
    
        protected MyClientCredentials(MyClientCredentials other)
            : base(other)
        {
            // Clone fields defined in this class.
            this.creditCardNumber = other.creditCardNumber;
        }
    
        public string CreditCardNumber
        {
            get
            {
                return this.creditCardNumber;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this.creditCardNumber = value;
            }
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            // Return your implementation of the SecurityTokenManager.
            return new MyClientCredentialsSecurityTokenManager(this);
        }
    
        protected override ClientCredentials CloneCore()
        {
            // Implement the cloning functionality.
            return new MyClientCredentials(this);
        }
    }
    
    Public Class MyClientCredentials
        Inherits ClientCredentials
        Private creditCardNumberValue As String
    
        Public Sub New()
    
        End Sub
    
        ' Perform client credentials initialization.    
        Protected Sub New(ByVal other As MyClientCredentials)
            MyBase.New(other)
            ' Clone fields defined in this class.
            Me.creditCardNumberValue = other.creditCardNumberValue
    
        End Sub
    
        Public Property CreditCardNumber() As String
            Get
                Return Me.creditCardNumberValue
            End Get
            Set
                If value Is Nothing Then
                    Throw New ArgumentNullException("value")
                End If
                Me.creditCardNumberValue = value
            End Set
        End Property
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            ' Return your implementation of the SecurityTokenManager.
            Return New MyClientCredentialsSecurityTokenManager(Me)
    
        End Function
    
        Protected Overrides Function CloneCore() As ClientCredentials
            ' Implement the cloning functionality.
            Return New MyClientCredentials(Me)
    
        End Function
    End Class
    

カスタム クライアント セキュリティ トークン マネージャーを実装するには

  1. ClientCredentialsSecurityTokenManager から派生する新しいクラスを定義します。

  2. 任意。 カスタム CreateSecurityTokenProvider(SecurityTokenRequirement) 実装を作成する必要がある場合は、SecurityTokenProvider メソッドをオーバーライドします。 カスタム セキュリティ トークン プロバイダーの詳細については、「方法: カスタム セキュリティ トークン プロバイダーを作成する」を参照してください。

  3. 任意。 カスタム CreateSecurityTokenAuthenticator(SecurityTokenRequirement, SecurityTokenResolver) 実装を作成する必要がある場合は、SecurityTokenAuthenticator メソッドをオーバーライドします。 カスタム セキュリティ トークン認証システムの詳細については、「方法: カスタム セキュリティ トークン認証システムを作成する」を参照してください。

  4. 任意。 カスタム CreateSecurityTokenSerializer を作成する必要がある場合は、SecurityTokenSerializer メソッドをオーバーライドします。 カスタム セキュリティ トークンおよびカスタム セキュリティ トークン シリアライザーの詳細については、「方法: カスタム トークンを作成する」を参照してください。

    internal class MyClientCredentialsSecurityTokenManager :
        ClientCredentialsSecurityTokenManager
    {
        MyClientCredentials credentials;
    
        public MyClientCredentialsSecurityTokenManager(MyClientCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(
            SecurityTokenRequirement tokenRequirement)
        {
            // Return your implementation of the SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenProvider(tokenRequirement);
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(
            SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of the SecurityTokenAuthenticator, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }
    
        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            // Return your implementation of the SecurityTokenSerializer, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenSerializer(version);
        }
    }
    
    
    Friend Class MyClientCredentialsSecurityTokenManager
        Inherits ClientCredentialsSecurityTokenManager
        Private credentials As MyClientCredentials
    
    
        Public Sub New(ByVal credentials As MyClientCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
    
        End Sub
    
    
        Public Overrides Function CreateSecurityTokenProvider( _
        ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider
            ' Return your implementation of the SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenProvider(tokenRequirement)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenAuthenticator( _
        ByVal tokenRequirement As SecurityTokenRequirement, _
        ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator
            ' Return your implementation of the SecurityTokenAuthenticator, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _
        As SecurityTokenSerializer
            ' Return your implementation of the SecurityTokenSerializer, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenSerializer(version)
    
        End Function
    End Class
    

アプリケーション コードによるカスタム クライアント資格情報を使用するには

  1. サービス インターフェイスを表す、生成されたクライアントのインスタンスを作成するか、または通信の対象となるサービスを指す ChannelFactory のインスタンスを作成します。

  2. Behaviors コレクションから、システム指定のクライアント資格情報の動作を削除します。このコレクションには、Endpoint プロパティからアクセスできます。

  3. カスタム資格情報クラスの新しいインスタンスを作成し、Behaviors コレクションに追加します。このコレクションには、Endpoint プロパティからアクセスできます。

    // Create a client with the client endpoint configuration.
    CalculatorClient client = new CalculatorClient();
    
    // Remove the ClientCredentials behavior.
    client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
    
    // Add a custom client credentials instance to the behaviors collection.
    client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
    
    ' Create a client with the client endpoint configuration.
    Dim client As New CalculatorClient()
    
    ' Remove the ClientCredentials behavior.
    client.ChannelFactory.Endpoint.Behaviors.Remove(Of ClientCredentials)()
    
    ' Add a custom client credentials instance to the behaviors collection.
    client.ChannelFactory.Endpoint.Behaviors.Add(New MyClientCredentials())
    

上記の手順は、アプリケーション コードからクライアント資格情報を使用する方法を示しています。 WCF の資格情報は、アプリケーション構成ファイルを使用して構成することもできます。 ソースの変更、再コンパイル、再展開を行うことなくアプリケーションのパラメーターを変更できるため、ハードコーディングを行うよりもアプリケーション構成ファイルの使用を一般にお勧めします。

次の手順では、カスタム資格情報の構成をサポートする方法について説明します。

カスタム クライアント資格情報の構成ハンドラーの作成

  1. ClientCredentialsElement から派生する新しいクラスを定義します。

  2. 任意。 アプリケーション構成を通じて公開する必要があるすべての追加構成パラメーターのプロパティを追加します。 次の例では、CreditCardNumber という名前のプロパティを追加します。

  3. BehaviorType プロパティをオーバーライドして、構成要素によって作成されたカスタム クライアント資格情報クラスの型を返します。

  4. CreateBehavior メソッドをオーバーライドします。 このメソッドは、構成ファイルから読み込まれた設定に基づいてカスタム資格情報クラスのインスタンスを作成して返す役割を担います。 このメソッドから ApplyConfiguration(ClientCredentials) 基本メソッドを呼び出し、カスタム クライアント資格情報インスタンスに読み込まれたシステム指定の資格情報の設定を取得します。

  5. 任意。 手順 2. で追加のプロパティを追加している場合は、Properties プロパティをオーバーライドして、追加した構成設定が構成フレームワークから認識されるよう登録します。 追加したプロパティを基本クラスのプロパティと結合して、このカスタム クライアント資格情報の構成要素を通じてシステム指定の設定が構成されるようにします。

    public class MyClientCredentialsConfigHandler : ClientCredentialsElement
    {
        ConfigurationPropertyCollection properties;
    
        public override Type BehaviorType
        {
            get { return typeof(MyClientCredentials); }
        }
    
        public string CreditCardNumber
        {
            get { return (string)base["creditCardNumber"]; }
            set
            {
                if (String.IsNullOrEmpty(value))
                {
                    value = String.Empty;
                }
                base["creditCardNumber"] = value;
            }
        }
    
        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                if (this.properties == null)
                {
                    ConfigurationPropertyCollection properties = base.Properties;
                    properties.Add(new ConfigurationProperty(
                        "creditCardNumber",
                        typeof(System.String),
                        string.Empty,
                        null,
                        new StringValidator(0, 32, null),
                        ConfigurationPropertyOptions.None));
                    this.properties = properties;
                }
                return this.properties;
            }
        }
    
        protected override object CreateBehavior()
        {
            MyClientCredentials creds = new MyClientCredentials();
            creds.CreditCardNumber = CreditCardNumber;
            base.ApplyConfiguration(creds);
            return creds;
        }
    }
    
    
    Public Class MyClientCredentialsConfigHandler
        Inherits ClientCredentialsElement
        Private propertiesValue As ConfigurationPropertyCollection
    
    
        Public Overrides ReadOnly Property BehaviorType() As Type
            Get
                Return GetType(MyClientCredentials)
            End Get
        End Property
    
        Public Property CreditCardNumber() As String
            Get
                Return CStr(MyBase.Item("creditCardNumber"))
            End Get
            Set
                If String.IsNullOrEmpty(value) Then
                    value = String.Empty
                End If
                MyBase.Item("creditCardNumber") = value
            End Set
        End Property
    
    
        Protected Overrides ReadOnly Property Properties() As ConfigurationPropertyCollection
            Get
                If Me.propertiesValue Is Nothing Then
                    Dim myProperties As ConfigurationPropertyCollection = MyBase.Properties
                    myProperties.Add(New ConfigurationProperty( _
                    "creditCardNumber", _
                    GetType(System.String), _
                    String.Empty, _
                    Nothing, _
                    New StringValidator(0, 32, Nothing), _
                    ConfigurationPropertyOptions.None))
                    Me.propertiesValue = myProperties
                End If
                Return Me.propertiesValue
            End Get
        End Property
    
    
        Protected Overrides Function CreateBehavior() As Object
            Dim creds As New MyClientCredentials()
            creds.CreditCardNumber = Me.CreditCardNumber
            MyBase.ApplyConfiguration(creds)
            Return creds
    
        End Function
    End Class
    

構成ハンドラー クラスを作成したら、WCF の構成フレームワークに統合できます。 これにより、次の手順で示すように、カスタム クライアント資格情報をクライアント エンドポイント動作要素で使用できるようになります。

カスタム クライアント資格情報構成ハンドラーをアプリケーション構成に登録して使用するには

  1. <extensions> 要素と <behaviorExtensions> 要素を構成ファイルに追加します。

  2. <add> 要素を <behaviorExtensions> 要素に追加し、name 属性に適切な値を設定します。

  3. type 属性を完全修飾型名に設定します。 また、アセンブリ名と他のアセンブリ属性を含めます。

    <system.serviceModel>
      <extensions>
        <behaviorExtensions>
          <add name="myClientCredentials" type="Microsoft.ServiceModel.Samples.MyClientCredentialsConfigHandler, CustomCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
      </extensions>
    </system.serviceModel>
    
  4. 構成ハンドラーの登録後は、システム指定の <clientCredentials> 要素の代わりに、同じ構成ファイル内でカスタム資格情報要素を使用できます。 システム指定のプロパティと、構成ハンドラーの実装に追加した任意の新規プロパティのどちらも使用できます。 次の例では、creditCardNumber 属性を使用して、カスタム プロパティの値を設定します。

    <behaviors>
      <endpointBehaviors>
        <behavior name="myClientCredentialsBehavior">
          <myClientCredentials creditCardNumber="123-123-123"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    

カスタム サービス資格情報を実装するには

  1. ServiceCredentials から派生する新しいクラスを定義します。

  2. 任意。 追加している新しい資格情報の値に API を提供するために新しいプロパティを追加します。 新しい資格情報の値を追加しない場合は、この手順を省略します。 次の例では、AdditionalCertificate プロパティを追加します。

  3. CreateSecurityTokenManager メソッドをオーバーライドします。 カスタム クライアント資格情報が使用されると、WCF インフラストラクチャによって、このメソッドが自動的に呼び出されます。 このメソッドは、SecurityTokenManager クラスの実装のインスタンスを作成して返す役割を担います (次の手順で説明)。

  4. 任意。 CloneCore メソッドをオーバーライドします。 この手順は、カスタム クライアント資格情報の実装に新しいプロパティまたは内部フィールドを追加する場合にのみ必要になります。

    public class MyServiceCredentials : ServiceCredentials
    {
        X509Certificate2 additionalCertificate;
    
        public MyServiceCredentials()
        {
        }
    
        protected MyServiceCredentials(MyServiceCredentials other)
            : base(other)
        {
            this.additionalCertificate = other.additionalCertificate;
        }
    
        public X509Certificate2 AdditionalCertificate
        {
            get
            {
                return this.additionalCertificate;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this.additionalCertificate = value;
            }
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return base.CreateSecurityTokenManager();
        }
    
        protected override ServiceCredentials CloneCore()
        {
            return new MyServiceCredentials(this);
        }
    }
    
    Public Class MyServiceCredentials
        Inherits ServiceCredentials
        Private additionalCertificateValue As X509Certificate2
    
        Public Sub New()
    
        End Sub
    
        Protected Sub New(ByVal other As MyServiceCredentials)
            MyBase.New(other)
            Me.additionalCertificate = other.additionalCertificate
        End Sub
    
    
        Public Property AdditionalCertificate() As X509Certificate2
            Get
                Return Me.additionalCertificateValue
            End Get
            Set
                If value Is Nothing Then
                    Throw New ArgumentNullException("value")
                End If
                Me.additionalCertificateValue = value
            End Set
        End Property
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            Return MyBase.CreateSecurityTokenManager()
    
        End Function
    
    
        Protected Overrides Function CloneCore() As ServiceCredentials
            Return New MyServiceCredentials(Me)
    
        End Function
    End Class
    

カスタム サービス セキュリティ トークン マネージャーを実装するには

  1. ServiceCredentialsSecurityTokenManager クラスから派生する新しいクラスを定義します。

  2. 任意。 カスタム CreateSecurityTokenProvider 実装を作成する必要がある場合は、SecurityTokenProvider メソッドをオーバーライドします。 カスタム セキュリティ トークン プロバイダーの詳細については、「方法: カスタム セキュリティ トークン プロバイダーを作成する」を参照してください。

  3. 任意。 カスタム CreateSecurityTokenAuthenticator 実装を作成する必要がある場合は、SecurityTokenAuthenticator メソッドをオーバーライドします。 カスタム セキュリティ トークン認証システムの詳細については、「方法: カスタム セキュリティ トークン認証システムを作成する」のトピックを参照してください。

  4. 任意。 カスタム CreateSecurityTokenSerializer(SecurityTokenVersion) を作成する必要がある場合は、SecurityTokenSerializer メソッドをオーバーライドします。 カスタム セキュリティ トークンおよびカスタム セキュリティ トークン シリアライザーの詳細については、「方法: カスタム トークンを作成する」を参照してください。

    internal class MyServiceCredentialsSecurityTokenManager :
        ServiceCredentialsSecurityTokenManager
    {
        MyServiceCredentials credentials;
    
        public MyServiceCredentialsSecurityTokenManager(MyServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenProvider(tokenRequirement);
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }
    
        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenSerializer(version);
        }
    }
    
    Friend Class MyServiceCredentialsSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
        Private credentials As MyServiceCredentials
    
        Public Sub New(ByVal credentials As MyServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
    
        End Sub
    
    
        Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) _
        As SecurityTokenProvider
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenProvider(tokenRequirement)
    
        End Function
    
        Public Overrides Function CreateSecurityTokenAuthenticator( _
        ByVal tokenRequirement As SecurityTokenRequirement, _
        ByRef outOfBandTokenResolver As SecurityTokenResolver) _
        As SecurityTokenAuthenticator
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _
        As SecurityTokenSerializer
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenSerializer(version)
    
        End Function
    End Class
    

アプリケーション コードによるカスタム サービス資格情報を使用するには

  1. ServiceHost のインスタンスを作成します。

  2. Behaviors コレクションから、システム指定のサービス資格情報の動作を削除します。

  3. カスタム サービス資格情報クラスの新しいインスタンスを作成し、これを Behaviors コレクションに追加します。

    // Create a service host with a service type.
    ServiceHost serviceHost = new ServiceHost(typeof(Service));
    
    // Remove the default ServiceCredentials behavior.
    serviceHost.Description.Behaviors.Remove<ServiceCredentials>();
    
    // Add a custom service credentials instance to the collection.
    serviceHost.Description.Behaviors.Add(new MyServiceCredentials());
    
    ' Create a service host with a service type.
    Dim serviceHost As New ServiceHost(GetType(Service))
    
    ' Remove the default ServiceCredentials behavior.
    serviceHost.Description.Behaviors.Remove(Of ServiceCredentials)()
    
    ' Add a custom service credentials instance to the collection.
    serviceHost.Description.Behaviors.Add(New MyServiceCredentials())
    

前の「To create a configuration handler for custom client credentials」および「To register and use a custom client credentials configuration handler in the application configuration」で説明した手順を使用して構成にサポートを追加します。構成ハンドラーの基本クラスとして、ClientCredentialsElement クラスではなく ServiceCredentialsElement クラスを使用する点のみが異なります。 カスタム サービス資格情報要素は、システム指定の <serviceCredentials> 要素を使用する場合にいつでも使用できます。

関連項目