認証が必要なソフトウェアを使用する際、登録費用はソフトウェアの利用者ではなく、開発者が支払うケースが多いです。同様に、開発者が日常的に使用するサードパーティコンポーネントも、利用料金を支払う必要があり、この場合の支払い主体は開発者であり、システムの最終利用者ではありません。
この二つの違いは以下の図のように表されます:
図1
本記事では.NET環境において認証が必要なサードパーティコントロールの開発方法について説明します。認証対象が開発者であることを前提として、認証の入口は開発者向けに提供し、最終ユーザーには見えないようにする必要があります。また、一般的に一度の認証は一つの開発者のみに許可されるため、認証情報は開発者のマシンと紐づける必要があります。これはハードウェア識別子との連携によって実現できます。ソフトウェアの公開後は、サードパーティコンポーネントがユーザーの使用に影響を与えてはならず、つまり公開後のコンポーネントは特定のマシンにバインドされることはできません。まとめると以下の点が重要です:
- コンポーネントの認証料金は、そのコンポーネントを使用してソフトウェアを開発する人に対して請求される;
- コンポーネントの認証はマシンに紐づけられ、一度の認証は一人の開発者のみが利用できる;
- ソフトウェアが公開された後は、コンポーネントが最終ユーザーに影響を与えてはならない。認証エントリは最終ユーザーには透明状態でなければならない。
これら三つの問題を解決するために、「デザイン時(Design-Time)」と「ランタイム時(Run-Time)」という重要な概念を理解する必要があります。それらの違いと関係性を把握することが求められます。
これまでのシリーズブログで学んだ通り:
**任意のコンポーネントは「デザイン時」と「ランタイム時」の二つの状態を持ちます。デザイン時とは、コンポーネントがフォームデザイナー内に存在するときの状態です。一方、ランタイム時はアプリケーションが実行されているときの状態です。同じコンポーネントでも、デザイン時とランタイム時の挙動は異なる可能性があります。まるで同じ人物が父親と息子の前で振る舞いが違うように、コンポーネントも状況によって挙動が変わるのです。**簡潔なコード例を示します:
1 class Component
2 {
3 public Component()
4 {
5 if (DesignTime)
6 {
7 // デザイン時処理
8 }
9 else
10 {
11 // ランタイム時処理
12 }
13 }
14 public void DoSomething()
15 {
16 if (DesignTime)
17 {
18 // デザイン時処理
19 }
20 else
21 {
22 // ランタイム時処理
23 }
24 }
25 }
View Code 上記コードのように、ソフトウェア開発段階では開発者がコンポーネントをフォームデザイナー上でインスタンス化する際に、現在のマシンでの認証状態(認証済み、試用期間、期限切れなど)を確認できます。この認証チェックは、現在のマシンのハードウェア情報を基に行われます。ソフトウェアが公開された後は、コンポーネントはデザイナー外にあり、最終ユーザーを対象とするため、通常は認証状態を確認する必要はありません。しかし、開発者が試用版のコンポーネントを使ってソフトウェアをリリースするのを防ぐために、公開後にもコンポーネントの認証状態を確認する必要があります。この際の認証方法はハードウェア情報と関連付ける必要はありません。
本デモでは待機用のプログレスバーを作成しました。このコンポーネントを使用するには認証が必要です。認証時には生成された申請コード(ローカルディスク番号と関連付け)を元に、コンポーネント開発元のアクティベーションコードと照合します。一致すれば認証成功となり、そうでなければ30日間の試用期間が与えられます。試用期間中はインターフェースに試用表示が表示され、期限が過ぎるとコンポーネントは使用できなくなります。公開する場合は、コンポーネントのメソッドを呼び出して申請コードとアクティベーションコードを渡すことで認証を行い、認証成功時は正常に動作し、失敗時は未認証表示が行われます(ただし最終ユーザーには認証を要求しません)。
コンポーネントの現在状態を判定するメソッド:
1 /// <summary>
2 /// コンポーネントの状態を確認
3 /// </summary>
4 void CheckStatus()
5 {
6 ISelectionService isp = GetService(typeof(ISelectionService)) as ISelectionService; //サービス取得
7 // 同じコンポーネントでも状態によって挙動が異なる
8 if (isp == null) // 公開時(またはランタイム時)
9 {
10 // 特に何もしない
11 }
12 else // 開発時(またはデザイン時)
13 {
14 if (AuthorizeHelper.CheckActivateCode(Properties.Settings.Default.ActivateCode, LocalMachine.GetAskCode())) // 認証状態をチェック
15 {
16 currentStatus = 1; // 開発時認証済み
17 }
18 else
19 {
20 using (frmAuthority frma = new frmAuthority()) // 認証ダイアログ
21 {
22 if (frma.ShowDialog() == DialogResult.OK) // 認証成功
23 {
24 currentStatus = 1;
25 }
26 else
27 {
28 if ((DateTime.Now - Properties.Settings.Default.TrialStart).TotalDays >= 30) // 試用期間終了判定
29 {
30 // 例外を投げる
31 throw new Exception("ProgressBarコンポーネントが認証されていません!");
32 }
33 else
34 {
35 currentStatus = 0; // 開発時試用
36 }
37 }
38 }
39 }
40 }
41 }
View Code 公開後、申請コードとアクティベーションコードを渡してコンポーネントを認証する:
1 /// <summary>
2 /// 公開時の認証エントリポイント
3 /// </summary>
4 /// <param name="askCode"></param>
5 /// <param name="activateCode"></param>
6 public void UnLock(string askCode, string activateCode)
7 {
8 if (AuthorizeHelper.CheckActivateCode(activateCode, askCode)) // 有効性を確認
9 {
10 currentStatus = 3; // 開発時(ランタイム時)認証済み
11 }
12 else
13 {
14 currentStatus = 2; // 開発時(ランタイム時)試用
15 }
16 }
View Code 注:本記事は主にサードパーティコンポーネントの認証原理について述べており、認証方式の安全性については今後の改善が必要です。
デモプロジェクト構造:
図2
表示効果:
1)開発段階におけるコンポーネント認証画面
図3
2)開発段階におけるProgressBarの試用期間
図4
3)公開後の認証されていないProgressBar
図5
4)開発段階における認証成功
図6
ソースコードダウンロードリンク:https://files.cnblogs.com/xiaozhi_5638/ComponentCopyProtection.rar
ご参考になれば幸いです!