ASP.NET Core 上的标识简介Introduction to Identity on ASP.NET Core

作者:Rick AndersonBy Rick Anderson

ASP.NET Core 标识是将登录功能添加到 ASP.NET Core 应用的成员资格系统。ASP.NET Core Identity is a membership system that adds login functionality to ASP.NET Core apps. 用户可以创建一个具有存储在标识中的登录信息的帐户,也可以使用外部登录提供程序。Users can create an account with the login information stored in Identity or they can use an external login provider. 支持的外部登录提供程序包括Facebook、Google、Microsoft 帐户和 TwitterSupported external login providers include Facebook, Google, Microsoft Account, and Twitter.

可以使用 SQL Server 数据库配置标识,以存储用户名、密码和配置文件数据。Identity can be configured using a SQL Server database to store user names, passwords, and profile data. 另外,还可以使用另一个永久性存储,例如 Azure 表存储。Alternatively, another persistent store can be used, for example, Azure Table Storage.

查看或下载示例代码如何下载)View or download the sample code (how to download)).

本主题介绍如何使用标识注册、登录和注销用户。In this topic, you learn how to use Identity to register, log in, and log out a user. 有关创建使用标识的应用的更多详细说明,请参阅本文末尾的后续步骤部分。For more detailed instructions about creating apps that use Identity, see the Next Steps section at the end of this article.

AddDefaultIdentity 和 AddIdentityAddDefaultIdentity and AddIdentity

ASP.NET Core 2.1 中引入了AddDefaultIdentityAddDefaultIdentity was introduced in ASP.NET Core 2.1. 调用 AddDefaultIdentity 类似于调用以下内容:Calling AddDefaultIdentity is similar to calling the following:

有关详细信息,请参阅AddDefaultIdentity 源See AddDefaultIdentity source for more information.

创建具有身份验证的 Web 应用Create a Web app with authentication

使用单个用户帐户创建一个 ASP.NET Core Web 应用程序项目。Create an ASP.NET Core Web Application project with Individual User Accounts.

  • 选择“文件” > “新建” > “项目”。Select File > New > Project.
  • 选择“ASP.NET Core Web 应用程序”。Select ASP.NET Core Web Application. 将项目命名为WebApp1 ,使其命名空间与项目下载相同。Name the project WebApp1 to have the same namespace as the project download. 单击 “确定”Click OK.
  • 选择 ASP.NET Core Web 应用程序,然后选择 "更改身份验证"。Select an ASP.NET Core Web Application, then select Change Authentication.
  • 选择单个用户帐户,然后单击 "确定"Select Individual User Accounts and click OK.

生成的项目提供ASP.NET Core 标识作为Razor 类库The generated project provides ASP.NET Core Identity as a Razor Class Library. 标识 Razor 类库公开 @no__t 为0的端点。The Identity Razor Class Library exposes endpoints with the Identity area. 例如:For example:

  • /Identity/Account/Login/Identity/Account/Login
  • /Identity/Account/Logout/Identity/Account/Logout
  • /Identity/Account/Manage/Identity/Account/Manage

应用迁移Apply migrations

将迁移应用到数据库初始化。Apply the migrations to initialise the database.

在包管理器控制台中运行以下命令(PMC):Run the following command in the Package Manager Console (PMC):

PM> Update-Database

测试注册和登录Test Register and Login

运行应用并注册用户。Run the app and register a user. 根据屏幕大小,你可能需要选择 "导航" 切换按钮以查看 "寄存器" 和 "登录" 链接。Depending on your screen size, you might need to select the navigation toggle button to see the Register and Login links.

查看标识数据库View the Identity database

  • 视图菜单中,选择SQL Server 对象资源管理器(SSOX)。From the View menu, select SQL Server Object Explorer (SSOX).
  • 导航到 (localdb) MSSQLLocalDB (SQL Server 13)Navigate to (localdb)MSSQLLocalDB(SQL Server 13). 右键单击dbo。AspNetUsers > 查看数据:Right-click on dbo.AspNetUsers > View Data:

在 AspNetUsers 表中 SQL Server 对象资源管理器的上下文菜单

配置标识服务Configure Identity services

服务添加到 ConfigureServicesServices are added in ConfigureServices. 典型模式是调用所有 Add{Service} 方法,然后调用所有 services.Configure{Service} 方法。The typical pattern is to call all the Add{Service} methods, and then call all the services.Configure{Service} methods.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

前面的代码用默认选项值配置标识。The preceding code configures Identity with default option values. 服务通过依赖关系注入提供给应用程序。Services are made available to the app through dependency injection.

通过调用UseAuthentication来启用标识。Identity is enabled by calling UseAuthentication. UseAuthentication 会将身份验证中间件添加到请求管道。UseAuthentication adds authentication middleware to the request pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseAuthentication();

    app.UseMvc();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings
        options.Password.RequireDigit = true;
        options.Password.RequiredLength = 8;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = true;
        options.Password.RequireLowercase = false;
        options.Password.RequiredUniqueChars = 6;

        // Lockout settings
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
        options.Lockout.MaxFailedAccessAttempts = 10;
        options.Lockout.AllowedForNewUsers = true;

        // User settings
        options.User.RequireUniqueEmail = true;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        // If the LoginPath isn't set, ASP.NET Core defaults 
        // the path to /Account/Login.
        options.LoginPath = "/Account/Login";
        // If the AccessDeniedPath isn't set, ASP.NET Core defaults 
        // the path to /Account/AccessDenied.
        options.AccessDeniedPath = "/Account/AccessDenied";
        options.SlidingExpiration = true;
    });

    // Add application services.
    services.AddTransient<IEmailSender, EmailSender>();

    services.AddMvc();
}

服务通过依赖关系注入提供给应用程序。Services are made available to the application through dependency injection.

通过在 @no__t 方法中调用 UseAuthentication,为应用程序启用标识。Identity is enabled for the application by calling UseAuthentication in the Configure method. UseAuthentication 会将身份验证中间件添加到请求管道。UseAuthentication adds authentication middleware to the request pipeline.

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Configure Identity
    services.Configure<IdentityOptions>(options =>
    {
        // Password settings
        options.Password.RequireDigit = true;
        options.Password.RequiredLength = 8;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = true;
        options.Password.RequireLowercase = false;

        // Lockout settings
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
        options.Lockout.MaxFailedAccessAttempts = 10;

        // Cookie settings
        options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(150);
        options.Cookies.ApplicationCookie.LoginPath = "/Account/Login";

        // User settings
        options.User.RequireUniqueEmail = true;
    });

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

这些服务通过依赖关系注入提供给应用程序。These services are made available to the application through dependency injection.

通过在 @no__t 方法中调用 UseIdentity,为应用程序启用标识。Identity is enabled for the application by calling UseIdentity in the Configure method. UseIdentity 会将基于 cookie 的身份验证中间件添加到请求管道。UseIdentity adds cookie-based authentication middleware to the request pipeline.

public void Configure(IApplicationBuilder app,
    IHostingEnvironment env, 
    ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseIdentity();

    // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

有关详细信息,请参阅IdentityOptions 类应用程序启动For more information, see the IdentityOptions Class and Application Startup.

基架注册、登录和注销Scaffold Register, Login, and LogOut

按照基架标识操作,并使用授权说明生成本部分中所示的代码。Follow the Scaffold identity into a Razor project with authorization instructions to generate the code shown in this section.

添加注册、登录和注销文件。Add the Register, Login, and LogOut files.

检查注册Examine Register

当用户单击 "注册" 链接时,将调用 RegisterModel.OnPostAsync 操作。When a user clicks the Register link, the RegisterModel.OnPostAsync action is invoked. 用户由CreateAsync_userManager 对象上创建。The user is created by CreateAsync on the _userManager object. _userManager 由依赖关系注入提供):_userManager is provided by dependency injection):

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            await _signInManager.SignInAsync(user, isPersistent: false);
            return LocalRedirect(returnUrl);
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

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

当用户单击 "注册" 链接时,将在 AccountController 上调用 Register 操作。When a user clicks the Register link, the Register action is invoked on AccountController. @No__t-0 操作可通过对 _userManager 对象调用 CreateAsync 来创建用户(通过依赖关系注入向 @no__t 提供):The Register action creates the user by calling CreateAsync on the _userManager object (provided to AccountController by dependency injection):

//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
            // Send an email with this link
            //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
            //await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
            //    "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
            await _signInManager.SignInAsync(user, isPersistent: false);
            _logger.LogInformation(3, "User created a new account with password.");
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }
        AddErrors(result);
    }

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

如果已成功创建用户,则会通过调用 _signInManager.SignInAsync 来登录用户。If the user was created successfully, the user is logged in by the call to _signInManager.SignInAsync.

注意: 请参阅帐户确认以了解在注册时要阻止立即登录的步骤。Note: See account confirmation for steps to prevent immediate login at registration.

登录Log in

发生下列情况时,会显示登录窗体:The Login form is displayed when:

  • 选择 "登录" 链接。The Log in link is selected.
  • 用户尝试访问他们无权访问的受限制的页面,未经系统的身份验证。A user attempts to access a restricted page that they aren't authorized to access or when they haven't been authenticated by the system.

提交“登录”页上的表单时,会调用 OnPostAsync 操作。When the form on the Login page is submitted, the OnPostAsync action is called. 会在 _signInManager 对象(通过注入依赖项的方式提供)上调用 PasswordSignInAsyncPasswordSignInAsync is called on the _signInManager object (provided by dependency injection).

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email, 
            Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

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

Controller 类公开了一个 User 属性,方便你通过控制器方法对其进行访问。The base Controller class exposes a User property that you can access from controller methods. 例如,可以枚举 User.Claims 并进行授权决策。For instance, you can enumerate User.Claims and make authorization decisions. 有关详细信息,请参阅 在 ASP.NET Core 中授权简介For more information, see 在 ASP.NET Core 中授权简介.

当用户选择 "登录" 链接或访问需要身份验证的页面时,将显示登录窗体。The Login form is displayed when users select the Log in link or are redirected when accessing a page that requires authentication. 当用户在登录页上提交窗体时,将调用 @no__t 0 Login 操作。When the user submits the form on the Login page, the AccountController Login action is called.

@No__t-0 操作对 _signInManager 对象调用 @no__t (通过依赖关系注入向 @no__t 提供)。The Login action calls PasswordSignInAsync on the _signInManager object (provided to AccountController by dependency injection).

//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(model.Email, 
            model.Password, model.RememberMe, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            _logger.LogInformation(1, "User logged in.");
            return RedirectToLocal(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning(2, "User account locked out.");
            return View("Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return View(model);
        }
    }

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

Base (ControllerPageModel)公开了 User 属性。The base (Controller or PageModel) class exposes a User property. 例如,可以枚举 User.Claims 来做出授权决策。For example, User.Claims can be enumerated to make authorization decisions.

注销Log out

"注销" 链接调用 LogoutModel.OnPost 操作。The Log out link invokes the LogoutModel.OnPost action.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                // This needs to be a redirect so that the browser performs a new
                // request and the identity for the user gets updated.
                return RedirectToPage();
            }
        }
    }
}

SignOutAsync清除 cookie 中存储的用户声明。SignOutAsync clears the user's claims stored in a cookie.

Pages/Shared/_LoginPartial.cshtml 中指定 post:Post is specified in the Pages/Shared/_LoginPartial.cshtml:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
    @if (SignInManager.IsSignedIn(User))
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="Identity"
               asp-page="/Account/Manage/Index"
               title="Manage">Hello@User.Identity.Name!</a>
        </li>
        <li class="nav-item">
            <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                   asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                   method="post">
                <button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
            </form>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
        </li>
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
        </li>
    }
</ul>


单击 "注销" 链接将调用 LogOut 操作。Clicking the Log out link calls the LogOut action.

//
// POST: /Account/LogOut
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LogOut()
{
    await _signInManager.SignOutAsync();
    _logger.LogInformation(4, "User logged out.");
    return RedirectToAction(nameof(HomeController.Index), "Home");
}

前面的代码调用 _signInManager.SignOutAsync 方法。The preceding code calls the _signInManager.SignOutAsync method. @No__t-0 方法会清除 cookie 中存储的用户声明。The SignOutAsync method clears the user's claims stored in a cookie.

测试标识Test Identity

默认 web 项目模板允许匿名访问主页。The default web project templates allow anonymous access to the home pages. 若要测试标识,请将[Authorize]添加到 "隐私" 页。To test Identity, add [Authorize] to the Privacy page.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        public void OnGet()
        {
        }
    }
}

如果已登录,请注销。运行应用并选择 "隐私" 链接。If you are signed in, sign out. Run the app and select the Privacy link. 你将重定向到登录页。You are redirected to the login page.

浏览标识Explore Identity

更详细地了解标识:To explore Identity in more detail:

标识组件Identity Components

所有标识相关 NuGet 包都包含在AspNetCore 元包中。All the Identity dependent NuGet packages are included in the Microsoft.AspNetCore.App metapackage.

标识的主包为AspNetCoreThe primary package for Identity is Microsoft.AspNetCore.Identity. 此包包含 ASP.NET Core 标识的核心接口集,是 Microsoft.AspNetCore.Identity.EntityFrameworkCore 提供的。This package contains the core set of interfaces for ASP.NET Core Identity, and is included by Microsoft.AspNetCore.Identity.EntityFrameworkCore.

迁移到 ASP.NET Core 标识Migrating to ASP.NET Core Identity

有关迁移现有标识存储的详细信息和指南,请参阅迁移身份验证和标识For more information and guidance on migrating your existing Identity store, see Migrate Authentication and Identity.

设置密码强度Setting password strength

有关设置最小密码要求的示例,请参阅配置See Configuration for a sample that sets the minimum password requirements.

后续步骤Next Steps