asp.net core 8 Authentication与Authorization

一、核心概念区分

  • 认证(Authentication):验证用户的身份,确认 "你是谁"。
    例如:用户输入用户名密码、使用 OAuth2 登录(如谷歌 / 微软账号)等,系统确认该用户的身份合法性。
  • 授权(Authorization):在认证通过后,决定用户 "能做什么"。
    例如:普通用户只能查看数据,管理员可以修改数据,系统通过授权规则限制访问权限。

1.1 标识框架

标识框架中提供了IdentityUser<TKey>IdentityRole<TKey>两个实体类型,其中的TKey代表主键的类型,因此IdentityUser<Guid>就代表使用Guid类型主键的用户实体类。我们可以在开发的时候直接使用IdentityUser<Guid>等类型,不过使用起来比较麻烦,因为每次都要声明主键的泛型类型,而且我们一般还需要为实体类增加额外的属性。因此我们一般编写继承自IdentityUser<TKey>IdentityRole<TKey>等的自定义类。

第1步,安装 Microsoft.AspNetCore.Identity.EntityFrameworkCore

创建ASP.NETCoreWebAPI项目,并通过NuGet安装Microsoft.AspNetCore.Identity.EntityFrameworkCore

第2步,创建用户实体类User和角色实体类Role

我们使用自增标识列类型的主键,因此我们编写分别继承自IdentityUser<long>IdentityRole<long>的User类和Role类

image

除了IdentityUserIdentityRole之外,标识框架中还有很多其他实体类,比如IdentityRoleClaim、IdentityUserClaim、IdentityUserLogin、IdentityUserToken等,一般情况下,我们不需要再编写这些实体类的子类。这些实体类有默认的表名,如果需要修改默认的表名或者对实体类进行进一步的配置,我们可以用EFCore中提供的IEntityTypeConfiguration来对实体类进行配置。

第3步,创建继承自IdentityDbContext的类

这是一个EFCore中的上下文类,我们可以通过这个类操作数据库。IdentityDbContext是一个泛型类,有3个泛型参数,分别代表用户类型、角色类型和主键类型

namespace Identity框架
{
    public class MyDbContext : IdentityDbContext<MyUser, MyRole, long>
    {
        public MyDbContext(DbContextOptions<MyDbContext> options)
       : base(options)
        {
        }
 
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
        }
    }
}

我们可以直接通过MyDbContext类来操作数据库,不过标识框架中提供了RoleManager、UserManager等类来简化对数据库的操作,这些类封装了对IdentityDbContext的操作。
标识框架中的方法有执行失败的可能,比如重置密码可能由于密码太简单而失败,因此标识框架中部分方法的返回值为Task<IdentityResult>类型。IdentityResult类型中有bool类型的Succeeded属性表示操作是否成功;如果操作失败,我们可以从Errors属性中获取错误的详细信息,由于有可能有多条错误信息,因此Errors是一个IEnumerable<IdentityError>类型的属性。IdentityError类包含Code(错误码)和Description(错误的详细信息)这两个属性。

image

第4步,注册与标识框架相关的服务

我们需要向依赖注入容器中注册与标识框架相关的服务,并且对相关的选项进行配置

builder.Services.AddDbContext<MyDbContext>(ops =>
{
    ops.UseSqlServer("server=.;database=Identity;uid=sa;pwd=[XXXXXX];TrustServerCertificate=True;");
});
builder.Services.AddDataProtection(); //安全地加密、解密应用程序中的敏感数据

builder.Services.AddIdentityCore<MyUser>(options => //注意不是Addldentity,Addldentity是传统MVC的
{
    options.Password.RequireDigit = false; //表示不再强制要求密码中包含数字。
    options.Password.RequireNonAlphanumeric = false; //表示不再强制要求密码中包含非字母数字字符(如 !@#$%^&* 等特殊符号)。
    options.Password.RequireLowercase = false; //表示不再强制要求密码中包含小写字母。
    options.Password.RequireUppercase = false; //表示不再强制要求密码中包含大写字母。
    options.Password.RequiredLength = 6; //表示密码的最小长度为6。
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider; //表示密码重置令牌提供程序的默认值。这意味着当用户请求重置密码时,系统会生成一个通过电子邮件发送的令牌,用户通过该令牌完成密码的重置操作。
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider; //表示电子邮件确认令牌提供程序的默认值。即当用户注册新账户后,系统会生成一个用于确认邮箱的令牌,并通过电子邮件发送给用户,用户点击链接或输入令牌以完成邮箱验证。
});

//IdentityBuilder是ASP.NET Core Identity提供的一个核心类,用于配置用户和角色相关的服务和功能。
//1. typeof(MyUser):指定了应用程序中使用的用户类型,这里是自定义的MyUser类,通常继承自IdentityUser,用于表示系统中的用户。
//2. typeof(MyRole):指定了应用程序中使用的角色类型,这里是自定义的MyRole类,通常继承自IdentityRole,用于表示系统中的角色。
var idBuilder = new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services);
/**
 * 这段代码通过IdentityBuilder配置了ASP.NET Core Identity框架,使其能够使用自定义的用户和角色类型(MyUser和MyRole),
 * 并将数据存储在Entity Framework Core的MyDbContext中。同时,它还注册了必要的管理器(UserManager和RoleManager)和默认的令牌提供程序,
 * 以支持用户和角色的全面管理功能,包括身份验证、授权、密码重置等常见操作。这些配置是构建安全、可扩展的身份验证和授权系统的基础。
 */
idBuilder.AddEntityFrameworkStores<MyDbContext>()
    .AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<MyRole>>()
    .AddUserManager<UserManager<MyUser>>();

因为过于简单的密码会带来系统的安全风险,所以标识框架默认对于密码的复杂度有苛刻的要求,比如密码中必须同时含有至少一个大写字母、一个小写字母、一个数字、一个特殊符号。这样严格的密码要求虽然能提高系统的安全性,但是用户用起来会非常麻烦。如果综合考虑项目的运营策略和安全等级等要求,需要调整这个密码的限制的话,我们就可以像第9~15行代码那样进行设置。我们在例子中设置的是非常宽松的密码要求:不要求小写字母、不要求大写字母、不要求数字、不要求特殊符号、长度最短为6,而且重置密码和确认邮箱的验证码也采用比较简单的生成值,便于用户输人。需要注意的是,这里的设置只是一个例子而已,读者需要根据项目的情况进行个性化的设置,以免由于密码要求太宽松而影响系统安全性。

  1. AddEntityFrameworkStores<MyDbContext>()

这个方法将Entity Framework Core作为存储后端,用于持久化用户和角色数据。<MyDbContext>指定了应用程序使用的DbContext类,这里是自定义的MyDbContext,通常继承自IdentityDbContext<MyUser, MyRole, ...>。通过这个方法,Identity会将用户和角色的数据存储到数据库中,并处理相关的数据库操作,如用户的创建、查询、更新和删除等。

  1. AddDefaultTokenProviders()

该方法为Identity添加了默认的令牌提供程序。这些令牌用于多种用途,比如用户账户的电子邮件确认、密码重置等。默认的令牌提供程序生成安全的令牌,这些令牌通过电子邮件或其他方式发送给用户,以验证其身份或执行特定的操作。

  1. AddRoleManager<RoleManager<MyRole>>()

这个方法向服务容器中注册了一个RoleManager<MyRole>实例,用于管理角色。RoleManager提供了创建、删除、查找和验证角色等功能。通过泛型参数MyRole,指定了应用程序中使用的角色类型。这使得应用程序能够使用角色来对用户进行分组和权限管理。

  1. AddUserManager<UserManager<MyUser>>()

最后,这个方法向服务容器中注册了一个UserManager<MyUser>实例,用于管理用户。UserManager提供了创建、删除、查找、验证用户以及管理用户密码、锁定状态等功能。通过泛型参数MyUser,指定了应用程序中使用的用户类型。这使得应用程序能够高效地管理用户账户及其相关操作。

第5步,生成表

通过执行Add-Migration、Update-database等命令执行EFCore的数据库迁移,然后程序就会在数据库中生成多张数据库表,这些数据库表都由标识框架负责管理,开发人员一般不需要直接访问这些表。

安装命令行工具

PM> Add-Migration Init
Add-Migration : 无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1
+ Add-Migration Init
+ ~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Add-Migration:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

.net 8 需要安装 Microsoft.EntityFrameworkCore.Tools

然后,项目现在的包,

<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.19" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.19" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.19" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.19">

先执行

PM> Add-Migration Init
Build started...
Build succeeded.
To undo this action, use Remove-Migration.

再执行

PM> Update-Database
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
....

image

第6步,MyUser添加字段

    public class MyUser: IdentityUser<long>
    {
        public DateTime CreateAt { get; set; }
    }

Add-Migration CreateAt

生成

20250830115815_CreateAt.cs

Update-Database

image

第7步,添加用户和角色

添加控制器

Test1Controller.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Data;
using System;

namespace Identity框架.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class Test1Controller : ControllerBase
    {
        private readonly RoleManager<MyRole> roleManager;
        private readonly UserManager<MyUser> userManager;

        public Test1Controller(RoleManager<MyRole> roleManager, UserManager<MyUser> userManager)
        {
            this.roleManager = roleManager;
            this.userManager = userManager;
        }


        [HttpPost]
        public async Task<IActionResult> CreateUser()
        {
            bool roleExists = await roleManager.RoleExistsAsync("admin");
            if (!roleExists)
            {
                MyRole role = new MyRole { Name = "Admin" };
                var r = await roleManager.CreateAsync(role); //AspNetRoles
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }
            }
            MyUser user = await this.userManager.FindByNameAsync("tss");
            if (user == null)
            {
                user = new MyUser { UserName = "tss", Email = "tangge@vip.qq.com", EmailConfirmed = true };
                var r = await userManager.CreateAsync(user, "123456"); //AspNetUsers
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }

                r = await userManager.AddToRoleAsync(user, "admin");  //AspNetUserRoles
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }
            }
            return Ok();
        }
    }
}
posted @ 2025-08-28 21:36  【唐】三三  阅读(38)  评论(0)    收藏  举报