- PR -

ASP.NETのThreadからネットワークリソースへの書き込み方法

1
投稿者投稿内容
mine
会議室デビュー日: 2002/10/25
投稿数: 9
投稿日時: 2002-10-25 16:45
ご存知の方どうか知恵をかしてください。

ASP.NETのC#プログラムから他のネットワーク上の他のPCの共有フォルダに
ファイルを出力しようとしています。

通常のプログラムではFileInfoクラスのCreateメソッドで作成することができるのですが
Threadを使用した場合には「ユーザー名を認識できないか、またはパスワードが間違っています。」
のエラーが発生します。

具体的には
ThreadTest test = new ThreadTest();
Thread t = new Thread(new ThreadStart(test.Test));
t.Start();
のように記述し、ThreadTestクラスのTestメソッドで他のPCの共有フォルダに
ファイルを作成しています。

どなたか方法をご存知ないでしょうか。よろしくお願いします。

環境
Windows2000
ASP.NET C#

web.configでは
<identity impersonate="true" />
を追加しユーザーの偽装をするように設定してあります。
NothingButXMLInfoSet
大ベテラン
会議室デビュー日: 2002/07/16
投稿数: 116
投稿日時: 2002-10-25 18:45
Windowsが扱うセキュリティトークンにはプロセストークンとスレッドトークンがあります。偽装によって、スレッドトークンが指定のユーザーのものに変化します。しかし、新しく作成されたスレッドのトークンは、作成したプロセストークンになります。したがって、スレッドを作成したらそのスレッド上で再び偽装をしなければ、そのスレッドはプロセストークンでネットワークアクセスを行うことになります。

以下のコードで、作成されたスレッドで偽装してネットワークフォルダにアクセスできます。ただし、このコードはブラウザがlocalhostにアクセスしている環境でなければ、ほとんどの場合まともに動作しませんので注意してください。

簡単に言ってしまうと、ブラウザ−Web−ファイルサーバーの3者がそれぞれ別のマシンである場合、3者が同一のドメインにいてしかもKerberosで認証されてしかも委任が可能な構成になっている場合、またはクリアテキストパスワードでIIS認証を受けている場合(IISマシンがユーザーの平文パスワードを知っている)のいずれかでなければ偽装は動作しません。詳細は拙著で恐縮ですがこちらをご覧になってください。

コード:
void ThreadProc() 	{
  WindowsIdentity ident = WindowsIdentity.GetCurrent();
  Label1.Text = ident.Name;
  WindowsImpersonationContext ctx = id.Impersonate();
  Label1.Text += WindowsIdentity.GetCurrent().Name;
  FileInfo f = new FileInfo(@"\\server\share\test.txt");
  f.Create().Close();
  ctx.Undo();
}

WindowsIdentity id;

private void Button1_Click(object sender, System.EventArgs e) {
  WindowsIdentity ident = WindowsIdentity.GetCurrent();
  Label2.Text = ident.Name;
  Button1.Text = Context.User.Identity.Name;
  ThreadStart ts = new ThreadStart(ThreadProc);
  id = ident;
  IAsyncResult ar = ts.BeginInvoke(null, null);
  try {
    ts.EndInvoke(ar);
  } catch (Exception ex) {
    Label2.Text += ex.Message;
  }
}

mine
会議室デビュー日: 2002/10/25
投稿数: 9
投稿日時: 2002-10-26 13:02
NothingBut.NETFXさん詳細な回答ありがとうございます。

ただ、今回はForm認証で認証することが決定しており、
ご回答いただいた方法で実行することができません。

そこで追加質問ですが
ASP.NETで重い処理(ここでネットワークリソースに出力する)を行うときに
レスポンスはクライアントに返してサーバーで処理を続行するようなことを
したかったのですが、なにか別の方法があるのでしょうか?
もしくはこのようなシステムはまれなのでしょうか?
NothingButXMLInfoSet
大ベテラン
会議室デビュー日: 2002/07/16
投稿数: 116
投稿日時: 2002-10-26 15:24
ASP.NETでForms認証を利用していようとPassportを利用していようと、ネットワーク上の共有フォルダにSMBでアクセスするときには関係ありません。必ずWindowsのユーザーが使われます。共有フォルダはWindowsの機能ですから。

Forms認証を使っているのであれば、おそらくIISの認証は匿名可の設定になっているでしょうから、IISの匿名ユーザーを共有フォルダにアクセス権があるドメインのユーザーにしてあげれば、上記のコードで動作するはずです。
mine
会議室デビュー日: 2002/10/25
投稿数: 9
投稿日時: 2002-10-28 09:42
回答いただいたコードを参考にして作成したところ正しく作成されました。

どうもありがとうございました。
大変助かりました。
1

スキルアップ/キャリアアップ(JOB@IT)