Restaurants WebAPI(四)——Identity

news2024/12/24 4:03:23

文章目录

  • 项目地址
  • 一、Authentication(身份认证)
    • 1.1 配置环境(解决类库包无法引用)
    • 1.2 使用Authentication控制Controller的访问
    • 1.3 获取User的Context
      • 1.3.1 在Application下创建User文件夹
        • 1. 创建`User.cs` record类封装角色信息
        • 2. 创建`UserContext.cs`提供接口给程序使用
        • 3. 注册IUserContext接口到服务里
    • 1.4 添加自己属性在User里
      • 1.4.1 给dbo.AspNetUsers添加字段
      • 1.4.2 添加IdentityController
      • 1.4.3 添加Command和Handler
        • 1. Command
        • 2. handler
  • 二、Authorization(授权)
    • 2.1 添加角色
    • 2.2 根据角色分配功能
      • 2.1.1 简单的授权
    • 2.3 添加权限用户的api
      • 2.3.1 添加管理用户的controller
      • 2.3.2 添加Command 和Handler
        • 1. Command
        • 2.Handler
    • 2.4 删除权限
      • 2.4.1 删除权限的Controller
      • 2.4.2 Command和Handler
        • 1. Command
        • 2. Handler


项目地址

  • 教程作者:
  • 教程地址:
  • 代码仓库地址:
  • 所用到的框架和插件:
dbt 
airflow

一、Authentication(身份认证)

回答“你是谁”的问题

1.1 配置环境(解决类库包无法引用)

  1. Restaurants.Domain层安装
 <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" />
  1. Restaurants.Domain层的Entities文件夹下创建User实体
using Microsoft.AspNetCore.Identity;

namespace Restaurants.Domain.Entities
{
    public class User:IdentityUser
    {
    }
}
  1. Restaurants.Infrastructure层的Persistence文件夹里DbContext继承改为 IdentityDbContext<User>

在这里插入图片描述

  1. 在Extensions里进行注册
 services.AddIdentityApiEndpoints<User>()
     .AddEntityFrameworkStores<RestaurantsDbContext>();
  1. 在引入AddIdentityApiEndpoints时,一直无法引入,原因是:在类库项目中不能直接引用WebApplicationBuilder、ApplicationBuilder等类,这些类位于Microsoft.ASPNetCore程序集中,但是无法通过Nuget包引用

在这里插入图片描述

  1. 在程序入口注册服务

app.MapGroup("api/identity").MapIdentityApi<User>();

  1. EF将User表写入数据库在类库Restaurants.Infrastructure
add-migration IdentityAdded
update-database
  1. 迁移成功后,数据库里就有了权限表
    在这里插入图片描述
  2. 发送一个post请求,注册一个用户

在这里插入图片描述

1.2 使用Authentication控制Controller的访问

  1. Restaurants.API层的Extensions文件夹 里注册服务

在这里插入图片描述

  1. 在需要添加验证的Controller类上面添加[Authorize],如果类里有不需要验证就可以访问的api,在该controller上添加[AllowAnonymous]

在这里插入图片描述
3. 设置成功后,当访问https://localhost:7044/api/restaurants/1报错401Unauthorized; 但是访问https://localhost:7044/api/restaurants可以获取所有restaurants的列表

1.3 获取User的Context

1.3.1 在Application下创建User文件夹

  • 创建User文件用来管理和获取权限中的User信息
    在这里插入图片描述
1. 创建User.cs record类封装角色信息
  • 将用户的Id, Email , Roles,封装到CurrentUser类里,并且通过IsInRole方法,检查用户的角色集合中是否包含指定的角色。返回true 或者 false
namespace Restaurants.Application.User
{
    public record CurrentUser(string Id, string Email, IEnumerable<string> Roles)
    {
        public bool IsInRole(string role) => Roles.Contains(role);
    }
}
2. 创建UserContext.cs提供接口给程序使用
  • 从当前 HTTP 请求的上下文中获取用户的身份信息(CurrentUser),并提供一个接口 IUserContext 供应用程序使用。
  • 主要逻辑:
    1. 获取IHttpContextAccessor服务httpContextAccessor
    2. 通过httpContextAccessor服务获取到HttpContext的User信息;
    3. 判断user信息,然后获取我们需要的内容;
    4. 将需要内容 new一个CurrentUser类;
    5. 创建一个IUserContext接口,该接口的功能,作用时注册到服务里,这样程序的任何地方只需要获取服务就可以获得CurrentUser的信息;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
namespace Restaurants.Application.User
{
    public interface IUserContext
    {
        CurrentUser? GetCurrentUser();
    }

    public class UserContext : IUserContext
    {
        private readonly IHttpContextAccessor httpContextAccessor;

        public UserContext(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
        }

        public CurrentUser? GetCurrentUser()
        {
            var user = httpContextAccessor?.HttpContext?.User;
            if (user == null)
            {
                throw new InvalidOperationException("User context is not present");
            }
            if (user.Identity == null || !user.Identity.IsAuthenticated)
            {
                return null;
            }
            var userId = user.FindFirst(c => c.Type == ClaimTypes.NameIdentifier)!.Value;
            var email = user.FindFirst(c => c.Type == ClaimTypes.Email)!.Value;
            var roles = user.Claims.Where(c => c.Type == ClaimTypes.Role)!.Select(c => c.Value);
            return new CurrentUser(userId, email, roles);
        }
    }
}
3. 注册IUserContext接口到服务里
  • 在Application的Extensions文件里注册 IUserContext的接口

在这里插入图片描述

1.4 添加自己属性在User里

1.4.1 给dbo.AspNetUsers添加字段

  • 现在我们的User使用的Identity自己定义,如果我们需要给User添加例如生日,国籍,等其他信息,就需要扩展
  1. Domian的Entities(Model)层里创建User.cs,表示自定义的User,继承IdentityUser的接口
using Microsoft.AspNetCore.Identity;

namespace Restaurants.Domain.Entities
{
    public class User:IdentityUser
    {
        public DateOnly? DateOfBirth { get; set; }
        public string? Nationality { get; set; }
    }
}
  1. 在Infrustructure层执行迁移,添加的字段加入到表里

1.4.2 添加IdentityController

  • 创建IdentitiesController.cs控制器,用来处理IdentityUser的增删改查
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Restaurants.Application.Users.Commands.UpdateUserDetials;

namespace Restaurants.API.Controllers
{
    [ApiController]
    [Route("api/identity")]
    public class IdentitiesController: ControllerBase
    {
        private readonly IMediator mediator;

        public IdentitiesController(IMediator mediator)
        {
            this.mediator = mediator;
        }

        [HttpPatch("user")]
        [Authorize]
        public async Task<ActionResult> UpdateUserDetails(UpdateUserDetailsCommand command)
        {
            await mediator.Send(command);
            return NoContent();
        }
    }
}

1.4.3 添加Command和Handler

在这里插入图片描述

1. Command
  • 添加UpdateUserDetailsCommand.cs文件,表示需要更新需要传递的属性
using MediatR;

namespace Restaurants.Application.Users.Commands.UpdateUserDetials
{
    public class UpdateUserDetailsCommand : IRequest
    {
        public DateOnly? DateOfBirth { get; set; }
        public string? Nationality { get; set; }
        public UpdateUserDetailsCommand(DateOnly dateOfBirth, string nationality)
        {
            DateOfBirth = dateOfBirth;
            Nationality = nationality;
        }
    }
}

2. handler
  • 创建UpdateUserDetailsCommandHandler.cs 需要注意的是:
    1. 获取的是private readonly IUserStore<User> userStore;服务;
    2. IUserStore<User> userStore里获取当前登录的用户信息;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Restaurants.Domain.Entities;
using Restaurants.Domain.Exceptions;

namespace Restaurants.Application.Users.Commands.UpdateUserDetials
{
    public class UpdateUserDetailsCommandHandler : IRequestHandler<UpdateUserDetailsCommand>
    {
        private readonly ILogger<UpdateUserDetailsCommandHandler> logger;
        private readonly IUserContext userContext;
        //是 ASP.NET Core Identity 提供的一个接口,定义了用于管理用户实体的基础存储操作。它是实现用户数据存储和管理的核心接口之一
        private readonly IUserStore<User> userStore;

        public UpdateUserDetailsCommandHandler
        (
            ILogger<UpdateUserDetailsCommandHandler> logger,
            IUserContext userContext,
            IUserStore<User> userStore
        )
        {
            this.logger = logger;
            this.userContext = userContext;
            this.userStore = userStore;
        }

        public async Task Handle(UpdateUserDetailsCommand request, CancellationToken cancellationToken)
        {
            logger.LogInformation("Update user details command handler");
            //1.获取当前用户
            var user = userContext.GetCurrentUser();
            //2.根据用户Id查找用户
            var dbUser = await userStore.FindByIdAsync(user!.Id, cancellationToken);

            if (dbUser == null)
            {
                throw new NotFoundException("User not found");
            }
            //3.更新用户信息
            dbUser.DateOfBirth = request.DateOfBirth;
            dbUser.Nationality = request.Nationality;

            //4.更新数据库
            await userStore.UpdateAsync(dbUser, cancellationToken);
        }
    }
}

二、Authorization(授权)

回答“回答的是“你能做什么”的问题”

2.1 添加角色

  1. 在餐厅系统里,我们需要添加三个不同的角色:用户,餐厅老板,以及管理员
  • 在Domain里创建Constants文件夹存放常量
  1. 将三个角色通过Seed添加到dbo.AspNetRoles表里

  2. 添加成功后,

在这里插入图片描述
4. 通过注册接口,将三个角色注册https://localhost:7044/api/identity/register

{
    "email":"user1@test.com",
    "password":"Password1!"
}
  1. 给每个用户分配权限在AspNetUserRoles表,手动插入
  insert into AspNetUserRoles
  (UserId,RoleId)
  VALUES
  ('aa18d542-ec4c-4d53-a709-f087a0218ee9','23fa674e-405b-4c5d-928f-d2aa3bfdd9f6'),
    ('30ad7ebe-6fb6-45fc-9ca4-d09c83df78e8','f7df975a-48dc-44b9-b047-619528fea585'),
      ('6cd69086-109f-4071-bc10-b528056a76f0','7bc860f9-b469-4df1-bc3f-ac7e1a459681')

2.2 根据角色分配功能

2.1.1 简单的授权

  1. 创建CreateRestaurant控制器上分配,只有Owner权限的人才可以访问该Api

  2. 登录之后,创建一个restaurants,发送请求

{
      "Name": "Tasty Tests3",
      "Description": "A cozy restaurant serving a variety of delicious dishes.",
      "Category": "Indian",
      "HasDelivery": true,
      "ContactEmail": "info@test.com",
      "ContactNumber": "555-1234",
      "City": "New York",
      "Street": "123 Main Street",
      "PostalCode": "10-010"
}
  1. 此时,还是403,因为我们没有给服务添加Roles的给功能,在Infrastructure/Extensions/ServiceCollectionExtensions.cs里,注册服务
    在这里插入图片描述

2.3 添加权限用户的api

2.3.1 添加管理用户的controller

``

    [HttpPost("userRole")]
    [Authorize(Roles = UserRoles.Admin)]
    public async Task<IActionResult> AssignUserRole(AssignUserRoleCommand command)
    {
        await mediator.Send(command);
        return NoContent();
    }

2.3.2 添加Command 和Handler

1. Command

AssignUserRoleCommand.cs

using MediatR;
namespace Restaurants.Application.Users.Commands.AssignUserRole;
public class AssignUserRoleCommand : IRequest
{
    public string UserEmail { get; set; } = default!;
    public string RoleName { get; set; } = default!;
}
2.Handler

AssignUserRoleCommandHandler.cs

using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Restaurants.Domain.Entities;
using Restaurants.Domain.Exceptions;
namespace Restaurants.Application.Users.Commands.AssignUserRole;
public class AssignUserRoleCommandHandler(ILogger<AssignUserRoleCommandHandler> logger,
    UserManager<User> userManager,
    RoleManager<IdentityRole> roleManager) : IRequestHandler<AssignUserRoleCommand>
{
    public async Task Handle(AssignUserRoleCommand request, CancellationToken cancellationToken)
    {
        logger.LogInformation("Assigning user role: {@Request}", request);
        var user = await userManager.FindByEmailAsync(request.UserEmail)
            ?? throw new NotFoundException(nameof(User), request.UserEmail);
        var role = await roleManager.FindByNameAsync(request.RoleName)
            ?? throw new NotFoundException(nameof(IdentityRole), request.RoleName);
        await userManager.AddToRoleAsync(user, role.Name!);
    }
}

2.4 删除权限

2.4.1 删除权限的Controller

  • Restaurants.API/Controllers/IdentityController.cs
    [HttpDelete("userRole")]
    [Authorize(Roles = UserRoles.Admin)]
    public async Task<IActionResult> UnassignUserRole(UnassignUserRoleCommand command)
    {
        await mediator.Send(command);
        return NoContent();
    }

2.4.2 Command和Handler

1. Command
  • Restaurants.Application/Users/Commands/UnassignUserRole/UnassignUserRoleCommand.cs
using MediatR;
namespace Restaurants.Application.Users.Commands.UnassignUserRole;
public class UnassignUserRoleCommand : IRequest
{
    public string UserEmail { get; set; } = default!;
    public string RoleName { get; set; } = default!;
}
2. Handler
  • Restaurants.Application/Users/Commands/UnassignUserRole/UnassignUserRoleCommandHandler.cs
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Restaurants.Application.Users.Commands.AssignUserRole;
using Restaurants.Domain.Entities;
using Restaurants.Domain.Exceptions;
namespace Restaurants.Application.Users.Commands.UnassignUserRole;
public class UnassignUserRoleCommandHandler(ILogger<UnassignUserRoleCommandHandler> logger,
    UserManager<User> userManager,
    RoleManager<IdentityRole> roleManager) : IRequestHandler<UnassignUserRoleCommand>
{
    public async Task Handle(UnassignUserRoleCommand request, CancellationToken cancellationToken)
    {
        logger.LogInformation("Unassigning user role: {@Request}", request);
        var user = await userManager.FindByEmailAsync(request.UserEmail)
            ?? throw new NotFoundException(nameof(User), request.UserEmail);
        var role = await roleManager.FindByNameAsync(request.RoleName)
            ?? throw new NotFoundException(nameof(IdentityRole), request.RoleName);
        await userManager.RemoveFromRoleAsync(user, role.Name!);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java-32 深入浅出 Spring - IoC 基础 启动IoC 纯注解方式 SpringConfig web.xml

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

Android Studio创建新项目并引入第三方so外部aar库驱动NFC读写器读写IC卡

本示例使用设备&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单&#xff0c;选择 要创建的项目模版&#xff0c;点击 Next 二、输入项目名称…

Trimble天宝三维激光扫描仪在建筑工程竣工测量中的应用【沪敖3D】

竣工测量是建筑项目竣工阶段的一个至关重要的环节&#xff0c;它为建筑工程的质量验收和成果核查提供了核心的参考依据。传统的竣工测量方法&#xff0c;如全站仪测量&#xff0c;主要依赖于现场人工操作&#xff0c;存在一些明显的局限性&#xff0c;例如作业时间长、工作量大…

java开发入门学习五-流程控制

流程控制语句 if&#xff0c; if...else&#xff0c; if..else if..else 与前端相同 略 switch case 与前端不同的是case不能使用表达式&#xff0c;使用表达式会报错 class TestSwitch {public static void main(String[] args) {// switch 表达式只能是特定的数据类型…

tslib(触摸屏输入设备的轻量级库)的学习、编译及测试记录

目录 tslib的简介tslib的源码和make及make install后得到的文件下载tslib的主要功能tslib的工作原理tslib的核心组成部分tslib的框架和核心函数分析tslib的框架tslib的核心函数ts_setup()的分析(对如何获取设备名和数据处理流程的分析)函数ts_setup()自身的主要代码ts_setup()对…

深度学习实战车辆目标跟踪【bytetrack/deepsort】

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对车辆目标数据集进行训练和优化&#xff0c;该数据集包含丰富的车辆目标图像样本…

unipp中使用阿里图标,以及闭坑指南

-----------------------------------------------------点赞收藏才是更新的动力------------------------------------------------- unipp中使用阿里图标 官网下载图标在项目中引入使用注意事项 官网下载图标 进入阿里图标网站 将需要下载的图标添加到购物车中 2. 直接下载…

《Vue3实战教程》5:响应式基础

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 响应式基础​ API 参考 本页和后面很多页面中都分别包含了选项式 API 和组合式 API 的示例代码。现在你选择的是 组合式 API。你可以使用左侧侧边栏顶部的“API 风格偏好”开关在 API 风格之间切换。 声明响应式状态…

【ue5学习笔记2】在场景放入一个物体的蓝图输入事件无效?

在场景放入一个物体的蓝图输入事件无效&#xff0c;那是因为你不知道gameMode这个东西这是一个用于设定游戏股则的东西&#xff0c; 就好比你的控制对象&#xff0c;你输入无效是没有指定你当前关卡中指定的控制对象是它。操作方法如下&#xff1a; 1.创建一个gameMode蓝图类并…

OnlineMusic项目测试报告

OnlineMusic项目测试报告 一、项目背景1.1 测试目标及测试任务的概括1.2 被测的系统&#xff0c;代码以及文档等信息 二、测试安排2.1 测试用例设计2.2 测试方案设计 三、测试分类3.1 测试方案3.1.1 功能测试3.1.2 自动化测试3.1.3 性能测试 3.2测试结果性能测试报告 一、项目背…

Webpack学习笔记(1)

1.为什么使用webpack? webpack不仅可以打包js代码&#xff0c;并且那个且支持es模块化和commonjs,支持其他静态资源打包&#xff0c;如图片、字体。。。 2.如何解决作用域问题&#xff1f; 作用域问题&#xff1a;例如loadsh等库&#xff0c;会绑定window对象&#xff0c;会…

信息安全管理与评估赛题第9套

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 赛题九 模块一 网络平台搭建与设备安全防护 1 赛项时间 共计180分钟。 2 赛项信息 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段 网络平台搭建与设备安全防护 任务1 网络平台搭建 XX:XX- XX:XX 50 任务2…

thinkphp5验证码captcha无法显示

排查思路 是否开启gd2以及gd2排查bom排查代码清除缓存 开启gd/gd2 找到php.ini 开启dg2库 去掉前面的;注释&#xff0c;有的可能会带.dll后缀影响不大 然后通过生成图片验证是否成功 查看是否存在bom 修改为utf-8即可&#xff0c;如果你的代码携带bom也需要排查一下 代码问…

90度Floating B to B 高速连接器信号完整性仿真

在180度 B to B Connector 信号完整性仿真时&#xff0c;不会碰到端口设置不方便问题&#xff0c;但在做90度B to B Connector信号完整性仿真时就会碰到端口设置问题。如下面的90度B to B Connector。 公座 母座 公母对插后如下&#xff1a; 客户要求改Connector需符合PCI-E3.…

ffmpeg翻页转场动效的安装及使用

文章目录 前言一、背景二、选型分析2.1 ffmpeg自带的xfade滤镜2.2 ffmpeg使用GL Transition库2.3 xfade-easing项目三、安装3.1、安装依赖([参考](https://trac.ffmpeg.org/wiki/CompilationGuide/macOS#InstallingdependencieswithHomebrew))3.2、获取ffmpeg源码3.3、融合xf…

用人话讲计算机:Python篇!(十五)迭代器、生成器、装饰器

一、迭代器 &#xff08;1&#xff09;定义 标准解释&#xff1a;迭代器是 Python 中实现了迭代协议的对象&#xff0c;即提供__iter__()和 __next__()方法&#xff0c;任何实现了这两个方法的对象都可以被称为迭代器。 所谓__iter__()&#xff0c;即返回迭代器自身 所谓__…

【计算机视觉基础CV-图像分类】02-入门详解图像分类、经典数据集、比赛与冠军图像模型演进史

前言 图像分类&#xff08;Image Classification&#xff09;是计算机视觉&#xff08;Computer Vision&#xff09;中一项基础且核心的任务。简单来说&#xff0c;就是让计算机从给定的类别集合中&#xff0c;为一张输入图片分配一个正确的类别标签。这个过程听起来直观&…

Docker_常用命令详解

这篇文章分享一下笔者常用的Docker命令供各位读者参考。 为什么要用Docker? 简单来说&#xff1a;Docker通过提供轻量级、隔离且可移植的容器化环境&#xff0c;使得应用在不同平台上保持一致性、易于部署和管理&#xff0c;具体如下 环境一致性&#xff1a; Docker容器使得…

CFA知识点梳理系列:CFA Level II, Reading 4 Big Data Projects

这是CFA知识点梳理系列的第四篇文章&#xff0c;前面的文章可以参考以下链接: CFA知识点梳理系列&#xff1a;CFA Level II, Reading 3 Machine Learning

自制数据库迁移工具-C版-06-HappySunshineV1.5-(支持南大Gbase8a、PostgreSQL、达梦DM)

目录 一、环境信息 二、简述 三、架构图 四、升级点 五、支持功能 六、后续计划支持功能 七、安装包下载地址 八、配置参数介绍 九、安装步骤 1、用户创建 2、安装包解压 3、环境变量配置 4、环境变量生效 5、动态库链接检验 &#xff08;1&#xff09;HsManage…