首页 > 编程语言 >Asp.Net Core鉴权授权:标识框架identity

Asp.Net Core鉴权授权:标识框架identity

时间:2022-09-21 21:56:48浏览次数:64  
标签:Core Asp await userManager options 标识 user Net public

在一个系统中,不是所有功能都能被自由地访问的,比如有的功能需要注册用户才能访问,有的功能需要VIP用户才能访问。针对资源的访问限制有两个概念:Authentication与Authorization,即鉴权与授权

  • Authentication:用来对访问者的用户身份进行验证;
  • Authorization:用来验证访问者的用户身份是否有对资源进行访问的权限。

通俗来说,Authentication是用来验证“用户是否登录成功”的,Authorization是用来验证“用户是否有权限访问”的。

标识框架identity

大部分系统中都需要通过数据库保存用户、角色等信息,并且需要注册、登录、密码重置、角色管理等功能。ASP.NET Core提供了标识(identity)框架,它采用RBAC(role-based access control,基于角色的访问控制)策略,内置了对用户、角色等表的管理及相关的接口,从而简化了系统的开发。标识框架还提供了对外部登录的支持。
标识框架中提供了IdentityUser<TKey>IdentityRole<TKey>两个实体类型,其中的TKey代表主键的类型,因此IdentityUser<Guid>就代表使用Guid类型主键的用户实体类。

接下来我们开始动手创建项目:

  1. 创建ASP.NET Core Web API项目,并通过NuGet安装Microsoft.AspNetCore.Identity.EntityFrameworkCore
  2. 创建用户实体类User和角色实体类Role。
public class User : IdentityUser<long>
{
	public DateTime CreationTime { get; set; }
	public string? NickName { get; set; }
}
public class Role : IdentityUser<long>
{
}

IdentityUser中定义了UserName(用户名)、Email(邮箱)、PhoneNumber(手机号)、PasswordHash(密码的哈希值)等属性,我们在User中又添加了CreationTime(创建时间)、NickName(昵称)两个属性。

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

  1. 创建继承自IdentityDbContext的类,这是一个EF Core中的上下文类,我们可以通过这个类操作数据库。IdentityDbContext是一个泛型类,有3个泛型参数,分别代表用户类型、角色类型和主键类型。
public class IdDbContext : IdentityDbContext<User, Role, long>
{
    public IdDbContext(DbContextOptions<IdDbContext> options): base(options)
    {
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}

我们可以直接通过IdDbContext类来操作数据库,不过标识框架中提供了RoleManager、UserManager等类来简化对数据库的操作,这些类封装了对IdentityDbContext的操作。

标识框架中的方法有执行失败的可能,比如重置密码可能由于密码太简单而失败,因此标识框架中部分方法的返回值为Task类型。IdentityResult类型中有bool类型的Succeeded属性表示操作是否成功;如果操作失败,我们可以从Errors属性中获取错误的详细信息,由于有可能有多条错误信息,因此Errors是一个IEnumerable类型的属性。IdentityError类包含Code(错误码)和Description(错误的详细信息)这两个属性。

  1. 我们需要向依赖注入容器中注册与标识框架相关的服务,并且对相关的选项进行配置。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

IServiceCollection services = builder.Services;
//对IdDbContext进行配置
services.AddDbContext<IdDbContext>(opt =>
{
    string connStr = builder.Configuration.GetConnectionString("Default");
   
    opt.UseSqlServer(connStr);
});
services.AddDataProtection();
//调用AddIdentityCore添加标识框架的一些重要的基础服务
//(我们没有调用AddIdentity方法,因为AddIdentity方法实现的初始化
// 比较适合传统的MVC模式的项目,而现在我们推荐用前后端分离开发模式。)
services.AddIdentityCore<User>(options =>
{
    // 对密码复杂度苛刻设置
    options.Password.RequireDigit = false;
    options.Password.RequireLowercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = false;
    options.Password.RequiredLength = 6;
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});
var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
//因为UserManager、RoleManager等服务被创建的时候需要注入非常多的服务,
//所以我们在使用标识框架的时候也需要注入和初始化非常多的服务
idBuilder.AddEntityFrameworkStores<IdDbContext>()
    .AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<Role>>()
    .AddUserManager<UserManager<User>>();


var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

还需安装Microsoft.EntityFrameworkCore.SqlServer包。并在配置文件中写入数据库连接字符串。

"ConnectionStrings": {
  "Default": "Data Source=.;Database=Customers;User ID=sa;Password=123456;MultipleActiveResultSets=True;"
}
  1. 通过安装Microsoft.EntityFrameworkCore.Tools包。然后执行数据库迁移Add-Migration createIdentityUpdate-database等命令执行EF Core的数据库迁移,然后程序就会在数据库中生成多张数据库表。这些数据库表都由标识框架负责管理,开发人员一般不需要直接访问这些表。
  2. 编写控制器的代码。我们在控制器中需要对角色、用户进行操作,也需要输出日志,因此通过控制器的构造方法注入相关的服务。
[ApiController]
[Route("[controller]/[action]")]
public class TestController : Controller
{
    private readonly ILogger<TestController> _logger;
    private readonly UserManager<User> _userManager;
    private readonly RoleManager<Role> _roleManager;
    public TestController(ILogger<TestController> logger, UserManager<User> userManager,
        RoleManager<Role> roleManager)
    {
        _logger = logger;
        _userManager = userManager;
        _roleManager = roleManager;
    }
    ......
}
  1. 编写创建角色和用户的方法。
[HttpPost]
public async Task<IActionResult> CreateUserRole()
{
    bool roleExists = await _roleManager.RoleExistsAsync("admin");
    if (!roleExists)
    {
        Role role = new Role { Name = "Admin" };
        var r = await _roleManager.CreateAsync(role);
        if (!r.Succeeded)
        {
            return BadRequest(r.Errors);
        }
    }
    User user = await _userManager.FindByNameAsync("lf");
    if (user == null)
    {
        user = new User
        {
            UserName = "lf",
            Email = "[email protected]",
            EmailConfirmed = true,
        };
        var r = await _userManager.CreateAsync(user, "111111");
        if (!r.Succeeded)
        {
            return BadRequest(r.Errors);
        }
        // 为用户添加角色
        r = await _userManager.AddToRoleAsync(user, "admin");
        if (!r.Succeeded)
        {
            return BadRequest(r.Errors);
        }
    }
    return Ok();
}
  1. 编写处理登录请求的操作方法Login。
public record LoginRequest(string UserName, string Password);
[HttpPost]
public async Task<IActionResult> Login(LoginRequest loginRequest)
{
    string userName = loginRequest.UserName;
    string password = loginRequest.Password;
    var user = await _userManager.FindByNameAsync(userName);
    if (user == null)
    {
        return NotFound($"用户名{userName}不存在!");
    }
    var islocked = await _userManager.IsLockedOutAsync(user);
    if (islocked)
    {
        return BadRequest("用户已锁定!");
    }
    var success = await _userManager.CheckPasswordAsync(user, password);
    if (success)
    {
        return Ok();
    }
    else
    {
        var r = await _userManager.AccessFailedAsync(user);
        if (!r.Succeeded)
        {
            return BadRequest("访问失败信息写入错误!");
        }
        else
        {
            return BadRequest("失败!");
        }
    }
}

标签:Core,Asp,await,userManager,options,标识,user,Net,public
From: https://www.cnblogs.com/nullcodeworld/p/16717260.html

相关文章

  • 一套 .NET开发的邮箱Mail开源库
    今天给大家推荐一个基于.Net开发的邮箱开源库。 邮箱在我们日常工作中,可以说是非常常见了。个人邮箱一般都是免费的,但企业邮箱会收费,虽然一般情况下,市面邮箱已经够用了......
  • Linux(Debian) 配置netcore环境
    一、准备工作    ①、开启粘贴板#进入defaults.vim【未安装vim,按需安装】linaro@linaro-alip:~$sudovi/usr/share/vim/vim81/defaults.vim#将setmouse=......
  • donet framework 4.8 WebApi 集成 websocket 的测试
    后端:C#.netframework4.8WebApi  usingSystem;usingSystem.Collections.Generic;usingSystem.Net;usingSystem.Net.Http;usingSystem.Net.WebSockets;usi......
  • windows下mingw64编译darknet过程中遇到的错误记录下
    ./examples/go.c:787:5:error:unknowntypename'fd_set';didyoumean'fpos_t'? 解决:      go.c文件中添加头文件#include<sys/select.h> ./include......
  • .Net 7内容汇总(2)--原始字符串
    在C#11里,添加了一个叫原始字符串的东西。这个东西算是我相当喜欢以及期待的功能。我们先来看看这玩意咋用。首先,我们先来看看之前如果我们需要定义一个带引号的字符串我们......
  • Net5 控制台程序引入Nlog 、Nlog配置文件解读
    十年河东,十年河西,莫欺少年穷学无止境,精益求精nlog是继log4Net后C#编程界又一颗闪亮的星,俗称superstar1、先学会使用1.1、新建控制台应用程序,引入如下nuget1、Micros......
  • 在.net平台C#程序防止被反编译效果测试
    在.net平台C#程序是目前较常用的编程语言,但其易被反编译的特点,一直是一个难题。今天看到一个防止反编译利器—外壳加密工具。加密后的效果还是杠杠滴。(看说明,对java程......
  • kubenetes基础概念
    1.工作流程1.1用户准备一个资源文件(记录了业务应用的名称,镜像地址信息),通过调用APIServer执行插件pod1.2APIServer收到用户的pod创建请求,将pod信息写入到etcd中1.3......
  • dotnet 为大型应用接入 ApplicationStartupManager 启动流程框架
    对于大型的应用软件,特别是客户端应用软件,应用启动过程中,需要执行大量的逻辑,包括各个模块的初始化和注册等等逻辑。大型应用软件的启动过程都是非常复杂的,而客户端应用软件......
  • .NET 6当中的Web API版本控制
    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进。为了了解ASP.NETCoreWebAPI的版本控制,我们必须了解......