Skip to content

MS_ASPNETIdentityExternalLogin

nishi_74322014 edited this page Aug 12, 2026 · 1 revision

ASP.NET Identityの外部ログイン

概要

外部ログイン・プロバイダを使用して外部ログインを簡単に実装できるが、
(プロトコルを理解してライブラリを自作するより数段楽ではあるものの)
実際は、そんなに簡単ではなかったりする。

プロバイダのプロトコル

外部ログイン・プロバイダとして使用可能な
クレームベース認証のプロトコルには、
以下のようなものがある。

プロトコル 状況
OAuth 現時点では、OAuth(正確には、OAuth 2.0)が主流である模様。OAuth 自体は認可プロトコルなので、外部ログインは拡張仕様である。
OpenID Connect その他、OpenID Connect に対応したライブラリも拡充しつつある。
OpenID Microsoft.Owin.Security.Google では、過去に OpenID を使用していた。
WS-Federation, SAML WIF(Windows Identity Foundation)によってサポート可能と思われる。

補足(最新化): この記述の時点から状況は整理され、
現在の外部ログインは実質すべて OpenID Connect である。

プロバイダ 現在
Google OIDC(accounts.google.com の Discovery あり)
Microsoft アカウント / Entra ID OIDC
Apple(Sign in with Apple) OIDC
Facebook 独自寄りの OAuth 2.0(Graph API)
X(旧 Twitter) OAuth 2.0(PKCE 必須。1.0a から移行済み)

OpenID Authentication 2.0(無印 OpenID)は 2014 年に廃止され、
現存しない。

なお「OAuth 自体は認可プロトコルなので、外部ログインは拡張仕様」
という指摘は極めて重要である。
アクセス トークンを受け取れたことは、認証の証明にならない
(トークンは他所で盗んだものかもしれない)。
だからこそ OpenID ConnectID トークン
必要になった、という経緯である。

ライブラリ

Owin.Securityライブラリ

  • Owin.Security 名前空間では、主要 IdP の STS に対応したライブラリが提供されている。
  • プロトコルは不問で、プロトコル・レベルの変更などもある模様。
    Microsoft.Owin.Security.Google では、過去に OpenID から OAuth 2.0 への
    変更などがあった模様。

Microsoft アカウント

補足: wl.* は旧 Live Connect のスコープで、
Microsoft Graph(openid profile email User.Read)に置き換わった。
現在は **Microsoft ID プラットフォーム(v2.0 エンドポイント)**を使う。

Google アカウント

移行メモ(最新化): 手順中の

  • 「Google Developers Console」→ 現在は Google Cloud Console
  • 「Google+ API を有効にする」→ Google+ API は 2019 年に廃止
    現在は有効化不要(プロフィール取得は OIDC の userinfo で行う)

である。

Facebook アカウント

Twitter アカウント

補足(この疑問への答え): OAuth 1.0a が正しい
Microsoft.Owin.Security.Twitter は OAuth 1.0a を実装している
(リクエスト トークン → 認可 → アクセス トークンの 3-legged)。

OAuth 1.0a はメッセージ自体に署名する方式のため、
署名の対象に URL(スキームを含む)が入る。
HTTPS 前提の実装になっているのはこのためである
(OAuth 2.0 は署名をやめ、TLS に依存する設計に変えた)。

なお X(旧 Twitter)は現在 OAuth 2.0 + PKCE に移行しており、
上記ライブラリは実質使えない。

Apple ID

  • 最近、Sign in with Apple(DNET_SignInWithApple.md)がリリースされたが、
    NuGet 上にライブラリは、まだ確認できない。
  • iOS 上での Native SDK が本丸なので、
    Web から外部ログインするための IdP としては、あまり使用されないかも。

補足(最新化): 現在は
AspNet.Security.OAuth.Appleaspnet-contrib)が広く使われている。
また、Apple はアプリ ストアの規約により
「他の外部ログインを提供するなら Sign in with Apple も提供せよ」
と求めているため、B2C では実質必須になっている。

実装上の癖として、

  • クライアント シークレットが JWT(ES256 署名、最長 6 か月)
    であり、定期的な再生成が要る
  • 氏名・メールは初回認可時にしか返らない(2 回目以降は空)ので
    その場で保存しなければならない
  • メール非公開を選ばれると @privaterelay.appleid.com
    中継アドレスになる

がある。

その他のライブラリ

OAuth用ライブラリ

Microsoft.Web.WebPages.OAuth.OAuthWebSecurity クラスには、
各サービスに応じて、アカウント認証を行うためのメソッドが用意されている。

項番 メソッド 処理内容
1 RegisterFacebookClient Facebook アカウントによる認証
2 RegisterGoogleClient Google アカウントによる認証
3 RegisterLinkedInClient LinkedIn アカウントによる認証
4 RegisterMicrosoftClient Microsoft アカウントによる認証
5 RegisterTwitterClient Twitter アカウントによる認証
6 RegisterYahooClient Yahoo アカウントによる認証

補足: これは MVC 4 時代の DotNetOpenAuth ベースの仕組みで、
現在は使用しないDotNetOpenAuth 自体が開発終了)。

OpenID Connect用ライブラリ

Microsoft.Owin.Security.OpenIdConnect では、
Microsoft Entra ID(Azure Active Directory)との、
OpenID Connect を使用した認証連携がサポートされている模様。

Google へのログインは現時点(2016 年)ではサポートされていない模様。

補足(最新化): 現在は Microsoft.AspNetCore.Authentication.OpenIdConnect
AddOpenIdConnect() で、Google を含む
Discovery(/.well-known/openid-configuration)に対応した
任意の OP
と連携できる。プロバイダ別のライブラリは基本的に不要になった。

.AddOpenIdConnect("google", o => {
    o.Authority = "https://accounts.google.com";
    o.ClientId = "...";
    o.ClientSecret = "...";
    o.ResponseType = "code";        // ← Implicit は使わない
    o.UsePkce = true;               // 既定 true
    o.Scope.Add("email");
    o.SaveTokens = true;
});

WS-Federation, SAML用ライブラリ

WIFの名前空間は、Microsoft.IdentityModel.Claims と、
OWIN ミドルウェア(Microsoft.Owin)と異なるため、
ASP.NET Identityとの連携具合が不明(多分連携していない)。

補足(最新化): ASP.NET Core には
Microsoft.AspNetCore.Authentication.WsFederation があり、
AD FS との連携が標準でできる。
SAML は標準では提供されず、
Sustainsys.Saml2 などのサードパーティを使う
SAMLを実装する。を参照)。

ASP.NET Core用ライブラリ

ASP.NET Core の情報は以下に纏まっている。

https://learn.microsoft.com/aspnet/core/security/authentication/social/

  • Google / Facebook / Microsoft / Twitter

※ こちらも、Owin.Security 同様に、MS 製(Microsoft.AspNetCore.Authentication)。

参考

  • 連載:Microsoft技術におけるアイデンティティ連携開発のいま - Build Insider
    http://www.buildinsider.net/web/msidentitydev
    • .NET で使えるアイデンティティ連携のためのライブラリまとめ(前・後編)
    • カスタム・アプリケーションによる認証フローとプログラミング

実装

以下の手順に従い、実装できる。

開始

外部ログインは、
HttpUnauthorizedResult
ActionResult を返すことで開始する。通常、redirect_uri は指定しない。

ハマり所

localhost

  • Microsoft アカウントでは、localhost も登録できるようになっている。
    しかし、Twitter では localhost が登録できないことを確認した。

  • 従って、localhost を使用できないログイン・プロバイダを使用する場合、
    URL, hosts, applicationhost.config の設定が必要になる。

企業プロキシ環境

  • 企業プロキシ環境下で外部サービスに接続
    プロキシ環境下で外部サービスに接続する場合、以下の実装・設定を行う必要がある。

    • ASP.NET Identity - プロキシ環境下で外部サービスによるユーザ認証を行う
      http://ichiroku11.hatenablog.jp/entry/2014/04/09/224050
    • この設定を行うと、下記の「Client の Web アプリ」からの Web アクセスは、
      企業プロキシ経由でインターネットにルーティングされるようになる。
  • 企業プロキシのフィルタリング

    • どこから、どこに、アクセスしようとしているかを確認する必要がある。
      OAuthに詳しくなると、以下にアクセスしていることが解るようになる。

      • User Agent から Client の Web アプリ(自分の開発中の Web アプリ)
      • User Agent から Authorization Server の Web アプリ(サービス側の Web アプリ)
      • Client の Web アプリから Authorization Server の Web アプリ
      • Client の Web アプリから Resource Server の WebAPI
      • User Agent から Resource Server の WebAPI
    • 例えば、Google アカウントでは、下記をフィルタ解除しているだけでは
      認証がうまく通らなかった。
      (恐らく仲介コードを使用し、Access Token や Claim を取得
      するための各エンドポイントの URL が異なるのだと思われる。)

      • https://www.google.com/
    • 従って、切り分けのために、企業プロキシの外からテストすることも重要になる。

補足(Google で許可すべきホスト): 上の推測は正しい。
OIDC ではブラウザが行く先とサーバが行く先が異なる

経路 ホスト
ブラウザ(認可) accounts.google.com
サーバ(トークン取得) oauth2.googleapis.com
サーバ(Discovery / JWKS) accounts.google.com, www.googleapis.com
サーバ(ユーザ情報) openidconnect.googleapis.com

ブラウザ側だけを許可しても、
サーバ→ Google のトークン交換で止まる
これが「認証がうまく通らない」の正体である。
.well-known/openid-configuration を実際に取得して、
出てくる URL のホストを許可リストに入れるのが確実である。

サービス側の仕様

サービス側の

  • 仕様が不明確なことや、
  • 仕様の変更が多いところがあり、

トラブる事が多い。

不明確

プロトコルも不定で、例えば OAuth 2.0 の場合、
詳しい仕様は記載されていないので
必要に応じて分析が必要になる(OAuthによる外部ログイン(認証)の研究(MS_OAuthExternalLoginResearch.md))。

変更

以下のように、インターフェイスの変更が多数あったことが報告されている。

また、過去 Google の OpenID の外部ログイン・プロバイダが存在しており、
最近 OAuth に置き換えられたことを考えると、
将来的には、OAuth が、OpenID Connect に置き換えられる。
などと言った可能性はある。

補足: この予測はその通りになった
現在、主要プロバイダの外部ログインはすべて OIDC である。
Discovery に対応した汎用の OIDC ミドルウェアを使っておけば、
プロバイダ側の変更に追従しやすい。

テンプレート実装の課題

ほぼ、AccountController.ExternalLoginCallback 周辺で完結する。

E-mailアドレス

  • 外部ログインをしても、既定で E-mail アドレスは取得できないので
    プロジェクト・テンプレートも、既定で E-mail アドレスを自分で手入力する
    という仕様で実装されている。

  • これでは、あまり外部ログインの意味が無いので(E-mail アドレスの再入力が必要)、
    検証済みの E-mail アドレスを取得できるように、
    連携先に、E-mail アドレスを要求するように設定する。

  • これにより、連携先から、検証済みの E-mail アドレスを取得できるようになるため、
    この E-mail アドレスを使用して、ユーザ登録し、外部ログインを追加すれば整合性が取れる。

  • しかし、この状態で、E-mail Confirmation を実装していると矛盾が生じる。

補足(メールをキーにしてはならない): 「連携先から取得した
検証済みメールでユーザを紐づける」という設計には重大な落とし穴がある。

  • email が検証済みとは限らない
    OIDC の email_verified クレームを必ず確認すること。
    false(または欠落)のメールで既存アカウントに紐づけると、
    攻撃者が任意のメールを名乗って他人のアカウントを乗っ取れる
  • メールは変わる。姓の変更・ドメイン移行で別人になる。

正しくは、iss + sub(プロバイダ + 不変のユーザ ID)の組
外部ログインのキーにする(AspNetUserLogins テーブルの
LoginProvider + ProviderKey がまさにこれ)。
メールは表示・照合の補助に留める。

Claimの保存

既定では Claim の保存処理は実装されていないので自分で実装する必要がある。

await UserManager.AddClaimAsync(user.Id, claim);

管理画面の外部ログインの削除の意味

  • ExternalLoginCallback の条件分岐で、外部ログインが有る時・無い時で動きが違う。

    • 外部ログインは、アカウントに追加される。
    • アカウントが作成されていない場合は、
      • サインアップ(アカウントの作成)から行なう。
      • その後、アカウントに外部ログインを追加してサインインする。
    • アカウントが作成されてる場合は、外部ログインをチェックする。
      • 外部ログインが存在しない場合は、外部ログインを追加してサインインする。
      • 外部ログインが存在する場合は、外部ログインを追加しないでサインインする。
  • 別のログイン手段を持たない場合は、外部ログインを削除できない仕様である模様(確認済)。

    • 最初にサインアップしてあれば、外部ログインを削除できる。
    • 2 つ以上の外部ログインがあれば、外部ログインを削除できる。
    • 最初に外部ログインした場合、サインアップできなくなる問題がある。
      • この場合、ローカル・サインインできなくなる。
      • パスワード・リセットすれば、ローカル・サインインできるようになる。
      • これでローカル・サインインができるようになれば、外部ログインを削除できる。

補足(この仕様は正しい): 「最後のログイン手段は削除させない」
という挙動は意図的な安全策である。
削除できてしまうと、ユーザは自分のアカウントに
二度とアクセスできなくなる(= 実質的なアカウント消失)。

同じ理由で、2FA を有効にしたら回復コードを必ず提示する
パスキーのみのアカウントには代替手段を残す、といった
「締め出し(lockout)」への配慮が要る。
アカウント回復の設計は、認証設計と同じだけ重要である。

外部ログインが失敗する

外部ログインが失敗することがあるらしい。

補足(現在の定番の原因): 外部ログインの「よく分からない失敗」は、
現在ではほぼ次のいずれかである。

症状 原因
コールバックで Correlation failed. 相関 Cookie が届いていないSameSite=None; Secure が必要(IdP から POST で戻る場合)
ローカルで動くが本番で失敗 リバース プロキシ配下でスキームが http になるUseForwardedHeaders が要る
redirect_uri_mismatch 上と同じ理由で redirect_urihttp:// で組み立てられている
断続的に失敗 Data Protection の鍵が共有されていない(状態の暗号化・復号に失敗)

特に 1 番目と 2 番目は、ロードバランサ / コンテナ導入時に必ず踏む

参考

Tsmatz


Tags: 移行, .NET開発, ASP.NET, ASP.NET MVC, ASP.NET Identity, OAuth, 認証基盤, セキュリティ

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally