web-dev-qa-db-ja.com

登録をキャンセルするUIとしての.NET Core Identity

.NET Core 2.1 + Identity as UIアプリケーションの「登録」オプションをキャンセルしたい。

もちろん、ページからボタンを単純に削除することができます、質問は-それは安全ですか?

そうでない場合、他のオプションは何ですか?足場を使用して登録コードを生成し、そこで無効にする必要がありますか?

(SetPasswordなども同様です)

ありがとう

22
kofifus

残念ながら、他の2つの答えは間違っています-質問は実際には、デフォルトのUIを提供するためにRazorページを使用する新しいAddDefaultIdentity()拡張機能を参照しています。これに対処する答えは、not質問で要求されたレジスタ機能を削除します。

バックグラウンド

AddDefaultIdentityはAddIdentityと同様の方法で機能しますが、新しいIDカミソリビュー(現在28個)へのアクセスをアプリに許可するAddDefaultUIへの呼び出しも含まれています。これらは新しいカミソリクラスライブラリにあります。これがAddDefaultIdentityとAddIdentityの唯一の違いではないことに注意してください(後述)。

デフォルトのビューを変更するには、プロジェクト内のビューをオーバーライド(「足場」)する必要があります。その後、それらを修正できます。ビューをオーバーライドしない場合、またはビューをオーバーライドしてからcshtmlファイルを削除した場合、デフォルトのUIバージョンに戻るだけです!たとえば、リンクを削除しても登録すると、ユーザーはURLを推測した場合でもデフォルトの登録ビューに移動できます。

オプション1-ビューのオーバーライド

いくつかのデフォルトビューを保持し、他のビューを修正または削除する場合は、次のようにビューをオーバーライドできます( from doc ):

  1. プロジェクトを右クリックし、[追加]> [新しい足場アイテム]を選択します。
  2. [足場の追加]ダイアログの左ペインから、[ID]> [追加]を選択します。
  3. [IDの追加]ダイアログで、必要なオプションを選択します

オーバーライドしたビューの外観と機能を単に変更するか、「削除」するために404を返すか、他の場所にリダイレクトすることができます。このオーバーライドされたビューを削除すると、デフォルトのUIが表示されます!

すべてのビューをオーバーライドする場合、このアプローチはすぐに面倒になります。

オプション2-デフォルトUIを追加しない

別のオプションは、AddDefaultUIを呼び出さないIDを追加する古い方法に戻ることです。欠点は、すべてのビューを自分で追加する必要があることです。次のようにしてこれを行うことができます( このドキュメントから -上記のオプション1に適用される、すべてのビューのオーバーライドに関する最初の行を無視します):

//remove this: services.AddDefaultIdentity<IdentityUser>()
//use this instead to get the Identity basics without any default UI:
services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

//this assumes you want to continue using razor views for your identity UI
//it specifies areas can be used with razor pages and then adds an 
//authorize filter with a default policy for the folder /Account/Manage and
//the page /Account/Logout.cshtml (both of which live in Areas/Identity/Pages)
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
    .AddRazorPagesOptions(options =>
    {
        options.AllowAreas = true;
        options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
        options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
    });

//configures the application cookie to redirect on challenge, etc.
services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = $"/Identity/Account/Login";
    options.LogoutPath = $"/Identity/Account/Logout";
    options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});

//configures an email sender for e.g. password resets
services.AddSingleton<IEmailSender, EmailSender>();

上記のように、AddDefaultIdentityとAddIdentityには別の違いがあるため、この2番目のアプローチにも問題がないと100%確信しているわけではないことに注意してください。たとえば、後者はRoleManagerサービスを追加しますが、前者は追加しません。また、これらのアプローチの両方が今後も同様にサポートおよび維持されるかどうかは不明です。

上記のオプションが何をしているのか疑問がある場合(そして、数時間殺す場合)、 AddDefaultIdentityのソースAddIdentityCookies および- AddIdentityCore )古いものと比較 AddIdentity

オプション3-ハイブリッドアプローチ

現時点での最良の選択肢は、おそらく前の2つを次のように組み合わせることです。

  1. デフォルトIDを使用するようにプロジェクトを設定します
  2. 含めたいビューだけを足場にして、それに応じて編集します
  3. 古いAddIdentity呼び出しに切り替えて、オプション2に示すように、カミソリオプションを含めます(含まれているビューに応じて必要に応じて調整します)

これで、必要なビューのみが作成され、デフォルトの実装に基づいているため、これらのビューのほとんどの作業が完了します。

7
Matt

ASP.NET Webページの場合、これは、ASP.Net razor Web Pagesを含めるための以前の回答のアドオンです。私は、誰かがそれらを必要とし、互いに混同しないようにこれらを分離しました。 Webページには、Webフォームのようにコードビハインドが含まれているため、異なります。

まず、ページ> _LoginPartial.cshtmlを編集します

<li><a asp-page="/Account/Register">Register</a></li>を削除

[ページの編集]> [アカウント]> [Login.cshtml]。以下を削除します。

                <div class="form-group">
                <p>
                    <a asp-page="./ForgotPassword">Forgot your password?</a>
                </p>
                <p>
                    <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
                </p>
            </div>

以下も削除します:

<div class="col-md-6 col-md-offset-2">
    <section>
        <h4>Use another service to log in.</h4>
        <hr />
        @{
            if ((Model.ExternalLogins?.Count ?? 0) == 0)
            {
                <div>
                    <p>
                        There are no external authentication services configured. See <a href="https://go.Microsoft.com/fwlink/?LinkID=532715">this article</a>
                        for details on setting up this ASP.NET application to support logging in via external services.
                    </p>
                </div>
            }
            else
            {
                <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                    <div>
                        <p>
                            @foreach (var provider in Model.ExternalLogins)
                            {
                                <button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                            }
                        </p>
                    </div>
                </form>
            }
        }
    </section>
</div>

Login.cshtml.csの背後にあるコードを編集します

削除する:

public IList<AuthenticationScheme> ExternalLogins { get; set; }

また削除:

// Clear the existing external cookie to ensure a clean login process
        await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

ページの編集>アカウント>管理> _ManageNav.cshtml

削除する:

    @if (hasExternalLogins)
{
    <li class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a asp-page="./ExternalLogins">External logins</a></li>
}

次に、ページ>アカウントディレクトリから次のファイルを削除します。

  • ExternalLogin.cshtml
  • ForgotPassword.cshtml
  • ForgotPasswordConfirmation.cshtml
  • Register.cshtml
  • ResetPassword.cshtml
  • ResetPasswordConfirmation.cshtml

Pages> Account> Manageディレクトリから次のファイルを削除します。

  • ExternalLogin.cshtml
6
pool pro

Model-View-Controller Webアプリケーションについて話していると思います。ボタンを削除するだけでなく、そのようなビューを削除することも安全ではないと言えます。

また、登録ユーザーを作成するサードパーティのログインを削除することも想定しています。

私は次のことをします:

アカウントコントローラーで次を削除します

[HttpGet]
    [AllowAnonymous]
    public IActionResult Register(string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await _userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
                await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);

                await _signInManager.SignInAsync(user, isPersistent: false);
                _logger.LogInformation("User created a new account with password.");
                return RedirectToLocal(returnUrl);
            }
            AddErrors(result);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

また、アカウントコントローラーで、さらに以下を削除します。

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public IActionResult ExternalLogin(string provider, string returnUrl = null)
    {
        // Request a redirect to the external login provider.
        var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Account", new { returnUrl });
        var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
        return Challenge(properties, provider);
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
    {
        if (remoteError != null)
        {
            ErrorMessage = $"Error from external provider: {remoteError}";
            return RedirectToAction(nameof(Login));
        }
        var info = await _signInManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return RedirectToAction(nameof(Login));
        }

        // Sign in the user with this external login provider if the user already has a login.
        var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in with {Name} provider.", info.LoginProvider);
            return RedirectToLocal(returnUrl);
        }
        if (result.IsLockedOut)
        {
            return RedirectToAction(nameof(Lockout));
        }
        else
        {
            // If the user does not have an account, then ask the user to create an account.
            ViewData["ReturnUrl"] = returnUrl;
            ViewData["LoginProvider"] = info.LoginProvider;
            var email = info.Principal.FindFirstValue(ClaimTypes.Email);
            return View("ExternalLogin", new ExternalLoginViewModel { Email = email });
        }
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginViewModel model, string returnUrl = null)
    {
        if (ModelState.IsValid)
        {
            // Get the information about the user from the external login provider
            var info = await _signInManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                throw new ApplicationException("Error loading external login information during confirmation.");
            }
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await _userManager.CreateAsync(user);
            if (result.Succeeded)
            {
                result = await _userManager.AddLoginAsync(user, info);
                if (result.Succeeded)
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
                    return RedirectToLocal(returnUrl);
                }
            }
            AddErrors(result);
        }

        ViewData["ReturnUrl"] = returnUrl;
        return View(nameof(ExternalLogin), model);
    }

また削除する

[HttpGet]
    [AllowAnonymous]
    public IActionResult ForgotPassword()
    {
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
            {
                // Don't reveal that the user does not exist or is not confirmed
                return RedirectToAction(nameof(ForgotPasswordConfirmation));
            }

            // For more information on how to enable account confirmation and password reset please
            // visit https://go.Microsoft.com/fwlink/?LinkID=532713
            var code = await _userManager.GeneratePasswordResetTokenAsync(user);
            var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme);
            await _emailSender.SendEmailAsync(model.Email, "Reset Password",
               $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
            return RedirectToAction(nameof(ForgotPasswordConfirmation));
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    [HttpGet]
    [AllowAnonymous]
    public IActionResult ForgotPasswordConfirmation()
    {
        return View();
    }

    [HttpGet]
    [AllowAnonymous]
    public IActionResult ResetPassword(string code = null)
    {
        if (code == null)
        {
            throw new ApplicationException("A code must be supplied for password reset.");
        }
        var model = new ResetPasswordViewModel { Code = code };
        return View(model);
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user == null)
        {
            // Don't reveal that the user does not exist
            return RedirectToAction(nameof(ResetPasswordConfirmation));
        }
        var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
        if (result.Succeeded)
        {
            return RedirectToAction(nameof(ResetPasswordConfirmation));
        }
        AddErrors(result);
        return View();
    }

    [HttpGet]
    [AllowAnonymous]
    public IActionResult ResetPasswordConfirmation()
    {
        return View();
    }

これで、[モデル]で次のファイルを削除できます。

  • ExternalLoginViewModel
  • ForgotPasswordViewModel
  • RegisterViewModel
  • ResetPasswordViewModel

ビューの下で私は削除します:

  • Eメール確認
  • ExternalLogin
  • パスワードをお忘れですか
  • ForgotPasswordConfirmation
  • 登録
  • パスワードを再設定する
  • ResetPasswordConfirmation

また、アカウントビューでLogin.cshtmlを編集し、次を削除します。

                <div class="form-group">
                <p>
                    <a asp-page="./ForgotPassword">Forgot your password?</a>
                </p>
                <p>
                    <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
                </p>
            </div>

以下も削除します:

<div class="col-md-6 col-md-offset-2">
    <section>
        <h4>Use another service to log in.</h4>
        <hr />
        @{
            if ((Model.ExternalLogins?.Count ?? 0) == 0)
            {
                <div>
                    <p>
                        There are no external authentication services configured. See <a href="https://go.Microsoft.com/fwlink/?LinkID=532715">this article</a>
                        for details on setting up this ASP.NET application to support logging in via external services.
                    </p>
                </div>
            }
            else
            {
                <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                    <div>
                        <p>
                            @foreach (var provider in Model.ExternalLogins)
                            {
                                <button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                            }
                        </p>
                    </div>
                </form>
            }
        }
    </section>
</div>

共有ビューで_LoginPartial.cshtmlを開き、次を削除します。

<li><a asp-area="" asp-controller="Account" asp-action="Register">Register</a></li>

[ビューの管理] _ManageNav.cshtmlで、次を削除します。

    @if (hasExternalLogins)
{
    <li class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a asp-action="ExternalLogins">External logins</a></li>
}

URL yourapp.com/Account/Registerにアクセスしても、404ページが表示されます。

お役に立てれば。

2
pool pro