業務イントラの認証 — Windows認証 / Forms認証 / Cookie の使い分けで業務SE が踏む選択

みなさんこんにちは!ヒロポンです!!

今回はASP.NET生存ガイド連載・第6回の本論記事。業務イントラASP.NETで認証どうする??の話。

ASP.NET案件のキックオフで「認証どうする??」と聞かれて、WinForms時代のWindowsIdentity.GetCurrent()感覚で答えようとして詰まったこと、ないっすか??ん?ASP.NETの認証って何種類あんねん?って手が止まる瞬間。

俺も流通系SIer時代に同じ場面を経験しました。イントラ業務系ASP.NET案件で「AD統合でSSOしたい」「フォームでログイン入力する画面が欲しい」「MFAも将来入れたい」みたいな要件が並んだ時、認証方式を3つから選ぶ判断軸が必要だと初めて気付いたんですよね。

結論から言うと、業務イントラASP.NET MVC 5の認証方式は3択で、業務系の大半はWindows認証で十分カタが付く:

  • Windows認証(Active Directory統合):イントラ専用・SSO・コード変更不要
  • Forms認証(Cookieベース):外部公開・独自ユーザー管理・標準実装
  • Cookie認証(OWIN / ASP.NET Identity): MFA・外部プロバイダ連携・モダン拡張

連載第1〜5回(View/Controller/Routing/ORM/DI)でView〜Action〜DBアクセスの流れを押さえたので、今回は「リクエストの認証/認可」を扱います。連載通奏低音のレイヤー分離思考が、今回は「認証レイヤー/認可レイヤー/セッションレイヤー」の3層分離に再拡張されます。

この記事ではVS2019 / .NET Framework 4.7.2 / C# 7.3 / ASP.NET MVC 5環境で、3方式の最小実装と、[Authorize]属性での認可制御、User.Identity.Nameでのユーザー名取得をコード5本でまとめます。後ろの「現場メモ」で、業務系チームでルール化した時の話も書いてる。

3行で結論:

  • 業務イントラ+ AD統合ありWindows認証一択(実装最も簡単・コード変更不要)
  • 外部公開+独自ユーザー管理Forms認証 or Cookie認証(パスワード自前管理)
  • MFA /外部プロバイダ連携Cookie認証(ASP.NET Identity)
目次

俺の体験—流通系SIer時代のイントラ認証案件

正直に書いておきます。俺が初めてASP.NET MVC 5で認証を扱ったのは流通系SIer時代のイントラ業務システム。要件は「社内PCからSSOで社員番号取れればいい」だけだったので、Windows認証一択で実装完了。web.configを3行書くだけで終わって、コード変更ゼロ。

その後、別案件で社外パートナー向けのASP.NET MVC 5受発注画面を作った時は、Forms認証(独自ユーザー管理)に切り替え。さらにその後、MFA必須の経営層向け画面ではCookie認証(OWIN + ASP.NET Identity)を導入。業務系イントラ= Windows認証で大半カタが付く・例外でForms / Cookie、という現場の判断軸が見えてきた経緯です。

連載通奏低音のレイヤー分離思考が今回は認証/認可/セッションレイヤーの3層に進化します:

  • 認証レイヤー:「あなたは誰か」を確認する(AD・パスワード・MFA)
  • 認可レイヤー:「あなたは何ができるか」を制御する([Authorize]属性・Role)
  • セッションレイヤー:認証結果を保持する(Cookie・Windowsトークン)

業務系の認証選びは、この3層の関心事を分離して考えると迷わないんですよね。

対応マップ— 3つの認証方式の比較

3方式を業務SE視点で6観点で比較すると、こんな感じになります:

観点 Windows認証 Forms認証 Cookie認証(Identity)
用途 イントラ+ AD統合 外部公開+独自ユーザー モダン拡張+ MFA
ID管理 Active Directory 自前DB ASP.NET Identity DB
SSO ✅(ドメイン参加PC) ❌(外部プロバイダ経由なら可)
MFA ❌(自前実装)
外部公開 ❌(VPN・モバイル不向き)
学習コスト 低(web.config + IISのみ) 高(OWIN設定)
パスワード管理 AD任せ 自前ハッシュ化必須 Identity標準実装

判断軸:

  • イントラ+ ADあり → Windows認証(実装コスト最小)
  • 外部公開+独自ユーザー → Forms認証
  • MFA /複数プロバイダ → Cookie認証(Identity)
  • 既存AD環境でCookieが要件 → Forms認証でADバインド

ここから順に、コード対比で見ていきます。

定石1: Windows認証—最小設定でイントラSSO

業務系イントラの最頻パターン。web.config 3行+ IIS設定で完結します:

<!-- ✅定石1: Windows認証のweb.config(最小設定)-->
<configuration>
  <system.web>
    <authentication mode="Windows" />
    <authorization>
      <deny users="?" />   <!--匿名ユーザーを拒否-->
    </authorization>
  </system.web>
</configuration>

IIS側の設定:

  1. サイトの認証で「Windows認証」を有効
  2. 「匿名認証」を無効
  3. アプリプールのIDがドメインユーザーでADに問い合わせできること

これでControllerのAction内でUser.Identity.Nameを呼ぶと、DOMAIN\username形式のユーザー名が取れます:

// ✅定石1: Action内でユーザー名取得
public class HomeController : Controller
{
    public ActionResult Index()
    {
        //ドメイン参加PCからアクセスすると自動的に取れる
        string userId = User.Identity.Name;   //例: "MYDOMAIN\\suzuki"
        bool isAuth = User.Identity.IsAuthenticated;   // true

        ViewBag.UserId = userId;
        return View();
    }
}

ポイント:

  1. コード変更ゼロweb.configとIIS設定のみ)
  2. SSO自動(ドメイン参加PCからアクセスすると自動でログイン状態)
  3. User.Identity.Nameで社員番号取得(ADアカウント名)
  4. 業務系イントラの大半はこれで完結

業務SEの判断軸: AD統合できる環境ならまずWindows認証。コード変更なしで実装が終わるので、学習コストが最も低い選択肢っす。

定石2: Forms認証—フォームログイン+ Cookie

外部公開or独自ユーザー管理が要る場合の標準パターン:

<!-- ✅定石2: Forms認証のweb.config設定-->
<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login"
             timeout="60"
             slidingExpiration="true"
             requireSSL="true" />
    </authentication>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>
// ✅定石2: Login ActionでのCookie発行
using System.Web.Security;

public class AccountController : Controller
{
    [AllowAnonymous]   //認証前でもアクセス可
    public ActionResult Login()=> View();

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginVm model, string returnUrl)
    {
        //自前DBでパスワード検証(ハッシュ化済み)
        var user = _userService.Authenticate(model.UserId, model.Password);
        if (user == null)
        {
            ModelState.AddModelError("", "IDまたはパスワードが違います");
            return View(model);
        }

        // Cookie発行(Forms認証)
        FormsAuthentication.SetAuthCookie(user.UserId, model.RememberMe);

        return Redirect(returnUrl ?? "/");
    }

    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Login");
    }
}

ポイント:

  1. FormsAuthentication.SetAuthCookie(userId, persistent)でCookie発行
  2. <forms timeout="60" slidingExpiration="true">で60分操作なしでログアウト、操作で延長
  3. requireSSL="true"でSSL必須化(本番運用の鉄則)
  4. パスワードハッシュ化は自前実装(PBKDF2 / Argon2をNuGetで)

業務系で外部公開ASP.NET MVC 5を作る時の本命。.NET Framework標準で追加NuGetなしで実装できるので、学習コストがCookie認証より低いっす。

定石3: Cookie認証— OWIN + ASP.NET Identity

モダンな選択肢。MFAや外部プロバイダ連携が要る場合:

// ✅定石3: OWIN Startup.csでのCookie認証設定
using Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.AspNet.Identity;

[assembly: OwinStartup(typeof(MyApp.Startup))]

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            ExpireTimeSpan = TimeSpan.FromMinutes(60),
            SlidingExpiration = true,
            CookieSecure = CookieSecureOption.Always,   // SSL必須

            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator
                    .OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user)=>
                            user.GenerateUserIdentityAsync(manager))
            }
        });

        //外部プロバイダ追加(Microsoft, Google, etc.)
        // app.UseMicrosoftAccountAuthentication(...);
        // app.UseGoogleAuthentication(...);
    }
}

ポイント:

  1. Install-Package Microsoft.AspNet.Identity.Owinで導入
  2. UseCookieAuthenticationでCookie認証ミドルウェア登録
  3. SecurityStampValidatorでセキュリティスタンプ検証(パスワード変更時に既存セッション無効化)
  4. 外部プロバイダ連携がASP.NET Identityの最大の旨み

学習コストはForms認証より高めですが、MFA / Googleログイン/ Microsoftアカウント連携が要件にあるならCookie認証一択。連載第5回(DI)で扱ったDIコンテナとの相性も良くて、UserManagerをUnityで注入する流れになります。

定石4: [Authorize]属性で認可制御

認証通過したユーザーに対する認可(何ができるか)[Authorize]属性で:

// ✅定石4: [Authorize] 属性で認可制御
public class OrderController : Controller
{
    [Authorize]   //ログイン必須(未ログインはLoginUrlにリダイレクト)
    public ActionResult Index()=> View();

    [Authorize(Roles = "Admin")]   // Admin Roleのユーザーのみ
    public ActionResult Delete(int id){ /* ... */ }

    [Authorize(Roles = "MYDOMAIN\\SalesGroup,MYDOMAIN\\ManagerGroup")]
    // Windows認証でAD Group制御(カンマ区切りでOR条件)
    public ActionResult Export(){ /* ... */ }

    [AllowAnonymous]   //認証不要([Authorize] のオーバーライド)
    public ActionResult Public()=> View();
}

// Controller全体に適用する場合
[Authorize]
public class SecuredController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()=> View();   //ここだけ匿名OK

    public ActionResult Dashboard()=> View();   //ログイン必須
}

ポイント:

  1. [Authorize]で未ログイン排除(LoginUrlにリダイレクト)
  2. [Authorize(Roles = "...")]でRole制御
  3. AD GroupもRoleとして使える(Windows認証時)
  4. [AllowAnonymous]でオーバーライド(Login Action等)

業務系の認可制御は[Authorize] + Roleの組み合わせで9割対応できる。データ単位の細かい認可(「自分の部署のデータだけ」等)はAction内でUser.Identity.Nameを見て自前判定するパターンっす。

定石5: User.Identity.Nameでユーザー情報取得

ログイン後のユーザー情報取得は3つのプロパティで:

// ✅定石5: User.Identityからの情報取得
public class HomeController : Controller
{
    [Authorize]
    public ActionResult Profile()
    {
        //認証済みか
        bool isAuth = User.Identity.IsAuthenticated;

        //ユーザー名(認証方式で形式が違う)
        string userName = User.Identity.Name;
        // Windows認証: "MYDOMAIN\\suzuki"
        // Forms認証: "suzuki"(SetAuthCookieで渡した値)
        // Cookie認証: "suzuki@example.com"(IdentityのUserName)

        // Role判定
        bool isAdmin = User.IsInRole("Admin");
        bool isInAdGroup = User.IsInRole("MYDOMAIN\\SalesGroup");

        // ClaimsIdentityから追加情報(Cookie認証時)
        if (User.Identity is System.Security.Claims.ClaimsIdentity claims)
        {
            string email = claims.FindFirst(System.Security.Claims.ClaimTypes.Email)?.Value;
        }

        return View();
    }
}

ポイント:

  • User.Identity.Nameで認証方式ごとに違う形式のID取得
  • User.IsInRole("Role名")でRole判定(AD Groupも使える)
  • ClaimsIdentityでCookie認証時の追加情報(メール/電話番号等)

業務系で「ログインユーザーの社員番号で部署を引きたい」「Adminだけメニュー表示」みたいな要件は、これらの基本APIで大半対応できる。複雑な認可はAuthorizeAttributeを継承して自前実装するパターンっす。

ハマりポイント—実体験ベースの本番事故3点

1. Windows認証でAD接続できずローカルIDで動いた(半日デバッガで追ってハマった)

開発機で動いていたWindows認証が、本番デプロイ後にローカルIDで動く事件。User.Identity.NameIIS APPPOOL\DefaultAppPoolみたいな値になっていて、社員番号取得できず画面が空白になった。半日デバッガで追ってハマった末に、IIS側の「匿名認証」が有効のままだったのが原因と判明。web.config<authentication mode="Windows"> + IISの「匿名認証OFF」+「Windows認証ON」の3点セット確認をチェックリスト化。

2. Forms認証のCookie有効期限切れで突然ログアウト(30分溶かした)

業務画面の入力中に突然ログイン画面に飛ばされて入力データがロストする事件。30分溶かした末に、<forms timeout="20">の20分タイムアウトが原因と判明。timeout="60" + slidingExpiration="true"に変更して、業務系の入力体験を改善。業務画面のCookie設定は60分+ slidingExpirationセットを業務系チーム規約に揃えた。

3. Cookie認証でSSL強制忘れでCookie漏洩リスク(数日プロファイラで追った)

開発環境をHTTPで動かしていた延長で本番もSSL強制を入れ忘れる事件。数日プロファイラで追ってようやく気付いた。<httpCookies requireSSL="true"> + <forms requireSSL="true">のSSL強制設定+ Cookie認証OWINのCookieSecure = CookieSecureOption.Alwaysで本番ではSSL必須化。本番デプロイ前にCookie系のSSL設定をチェックリスト化を業務系チーム規約に。

俺の現場メモ—業務系チームでの認証規約

流通系SIer時代に過去ASP.NET MVC 5案件をgrep -rnE "authentication mode|FormsAuthentication|UseCookieAuthentication" .で50箇所近くひっかけたら、Windows認証なのに<authentication mode="Forms">残骸・Forms timeout=10で短すぎ・Cookie認証HTTPのままが全部入りだった。後輩と一緒に3行ルールにまとめた:

  1. イントラ+ ADあり= Windows認証寄せ、外部公開= Forms認証、MFA = Cookie認証(判断軸を持つ)
  2. Forms認証はtimeout=60 + slidingExpiration=true + requireSSL=true(業務系の入力体験)
  3. 本番デプロイ前にSSL設定+認証mode + IIS設定の3点セット確認(チェックリスト化)

このルール化で、認証周りの本番事故が消えた。判断軸を持つ+書き方を揃えるだけで保守工数と事故率が両方下がるおすすめルールっす。

まとめ

状況 推奨認証方式
イントラ+ AD統合 Windows認証(web.config 3行+ IIS設定)
外部公開+独自ユーザー Forms認証+ Cookie +自前パスワード管理
MFA /外部プロバイダ Cookie認証(OWIN + ASP.NET Identity)
Cookie有効期限 timeout=60 + slidingExpiration=true
SSL強制 requireSSL=true + httpCookies requireSSL=true
認可制御 [Authorize]属性+ Role
ユーザー情報取得 User.Identity.Name / User.IsInRole() / ClaimsIdentity
Login Action [AllowAnonymous]でオーバーライド

業務イントラの認証は、「3層分離(認証/認可/セッション)」「判断軸3つ(イントラ/外部公開/MFA)」「SSL強制」の3点で9割困らなくなります。業務系イントラの大半はWindows認証で十分カタが付くので、AD統合できる環境ならWindows認証寄せが現実解。次回(連載第7回)は「CSSが効かない時のチェックリスト10項目」を扱うので、認証通過後のUI表示まわりのトラブルシューティングに進みます。

よくある質問

Q1.業務イントラのASP.NET MVC 5で認証方式はどう選べばいい?

A.判断軸は3点。イントラ専用+ AD統合あり→ Windows認証(実装最も簡単・コード変更不要)/ 外部公開+独自ユーザー管理→ Forms認証or Cookie認証(パスワード自前管理)/ MFA・外部プロバイダ連携必要→ Cookie認証(ASP.NET Identity)。業務系イントラの大半はWindows認証で十分カタが付くので、AD統合できる環境ならWindows認証寄せが現実解です。

Q2. Windows認証でADが繋がらない時、どこを見ればいい?

A. 3点をチェックします。(1)web.config<authentication mode="Windows">が設定されているか、(2)IISのサイト設定で「Windows認証」が有効・「匿名認証」が無効か、(3)アプリプールのIDがドメインユーザーでADに問い合わせできるか。AD接続できないと匿名アクセス扱いでUser.Identity.Nameが空文字になる「ローカルID誤動作」が起きるので、3点を順に確認するのが業務SE鉄則です。

Q3. Forms認証のCookie有効期限切れで突然ログアウトされる時は?

A. <forms timeout="分数">の値を確認してください。web.config<authentication><forms timeout="30">が30分なら、30分操作なしでログアウト。業務系で「画面入力中にCookie切れて入力データロスト」事故を防ぐには、timeout="60"程度に伸ばす+ slidingExpiration="true"で操作のたびに有効期限延長する設定がおすすめ。SSL必須(requireSSL="true")も合わせて確認です。

Q4. [Authorize]属性のRole名で大文字小文字の差で詰まる時は?

A. ADのRole名は大文字小文字を厳密に区別します。[Authorize(Roles = "DOMAIN\\SalesGroup")]と書く時、AD側のGroup名がSALESGROUPでもsalesgroupでも一致しない。AD側の正式表記をコピペするか、User.IsInRole("...")で一旦テスト出力して確認してから[Authorize]に書くのが業務SE定番の予防策です。

Q5. Cookie認証はSSL必須って本当?

A. 本番運用ではSSL必須です。Cookie認証は認証トークンをCookieに乗せて送るので、HTTP(平文)で送信するとWiresharkなどでCookieが抜き取られてなりすましができてしまう。<httpCookies requireSSL="true">でSSL必須化、<forms requireSSL="true">も合わせて設定。開発環境ではHTTPも許可することがありますが、本番ではSSL強制が業務SE鉄則です。

ここまでで認証3方式・認可制御・User.Identity取得・SSL強制は押さえた。次回はCSSのトラブルシューティングを扱うので、認証通過後のUI表示まわりに進みます。連載・WinFormsの隣接トピックも貼っておきます。

関連記事

ASP.NET生存ガイド・連載目次

今回はWinForms業務SEのためのASP.NET生存ガイド全10回の第6回です。

以上!

同じ罠でハマってる業務SE仲間いたら、どんどんシェア待ってるぜ!!

執筆者

バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る

この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次