おーみんブログ

C#, ASP.NET Core, Unityが大好きです。

ASP.NET Core + C# + Google Authenticatorで2要素認証の仕組みを実装してみた!

はじめに

ASP.NET Core + C# + Google Authenticatorを用いて2要素認証を実装してみました。
と言ってもあくまでGoogle Authenticatorに絞っており、事前のログイン機能については実装していません...。

利用したライブラリ

1から実装するのは大変だったので以下のライブラリを用いました。

github.com

実際の画面

Google Authenticator】

【認証キーを入力】

【検証結果】

【誤った認証キーを入力】

【検証結果】

サンプルコード

[HomeController.cs]

public class HomeController : Controller
{
    private readonly string _secretKey = "THISISSECRETKEY";
    private readonly TwoFactorAuthenticator _tfa = new TwoFactorAuthenticator();

    public IActionResult Index()
    {
        var setupInfo = _tfa.GenerateSetupCode("test_authenticator", "example.com", _secretKey, false);
        ViewData["qrCodeImageUrl"] = setupInfo.QrCodeSetupImageUrl;
        return View();
    }

    [HttpPost]
    [AutoValidateAntiforgeryToken]
    public IActionResult Authenticate(string userPin)
    {
        var isCorrectPIN = _tfa.ValidateTwoFactorPIN(_secretKey, userPin, TimeSpan.FromSeconds(45));
        ViewData["message"] = isCorrectPIN ? "OK" : "Error";
        return View("Index");
    }
}

[index.cshtml]

<div class="text-center">
    <img src="@ViewData["qrCodeImageUrl"]" />

    @using(Html.BeginForm(
        "Authenticate",
        "Home",
        null,
        FormMethod.Post
    ))
    { 
        <input type="text" name="userPin" />
        <input type="submit" />
    }
    @if(ViewData["message"] != null) 
    { 
        <div>@ViewData["message"]</div>
    }
</div>

HomeController.csを少し解説

var setupInfo = _tfa.GenerateSetupCode("test_authenticator", "example.com", _secretKey, false);

GenerateSetupCodeメソッドの第一引数はissuerを表します。Google Authenticatorアプリを開いた際に認証キーの上に出る値ですね。
第二引数は対象サイトを、第三引数はサーバ側で認証キーを検証するための秘密キーです。

上記のサンプルコードではコードにべた書きしていますが、実際には外部ファイルなどで保持し、なおかつさらに複雑な値にするのが好ましいです。
第四引数は秘密鍵をbase32に変換するかしないかという設定値です。

var isCorrectPIN = _tfa.ValidateTwoFactorPIN(_secretKey, userPin, TimeSpan.FromSeconds(45));

上記はユーザが入力した認証キーを検証しています。

第三引数はユーザが入力した認証キーのタイムラグ許容範囲です。
ライブラリの中身を見た感じだと30秒より大きな値が入った場合に30で割った値分の認証キーが許可される感じでした。そのため、上記の場合は1つ前の認証キーまでがOKとなります。

おわりに

本当は1から実装してみたかったのですが、ちょっと僕の実力がまだまだで理解しきれなかったためライブラリを利用しました。
そのうちまた再チャレンジしてみたいですな~。