Restaurants WebAPI(四)——Identity


文章目录

  • 项目地址
  • 一、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
    • 2.5 基于自定义声明的授权
      • 2.5.1 添加自定义属性给身份验证
      • 2.5.2 添加claim属性验证,对国籍进行认证
      • 2.5.3 封装认证的Policy
      • 2.5.4 添加对年龄的认证
    • 2.6 基于资源的授权


项目地址

  • 教程作者:
  • 教程地址:
  • 代码仓库地址:
  • 所用到的框架和插件:
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!);
    }
}

2.5 基于自定义声明的授权

  • 存在问题:现有的用户的验证只有一些很基础的,例如用户名,用户密码,角色等。如果,需要验证其他的,例如用户的国籍,用户的年龄才可以访问页面,就需要添加自定义的属性;

例如:给user1 添加了属性NationalityDateOfBirth ,判断之后添加这两个属性到程序Identity里,之后,我们可以通过判断用户是否有国际,或者生日计算的年龄,判断用户是否可以访问api;检查用户是否有 Nationality 和 DateOfBirth 属性。如果存在,向用户的声明列表中添加自定义声明;

2.5.1 添加自定义属性给身份验证

通过继承UserClaimsPrincipalFactory,override里面的方法实现

  1. 创建Restaurants.Infrastructure/Authorization/RestaurantsUserClaimsPrincipalFactory.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Restaurants.Domain.Entities;
using System.Security.Claims;


namespace Restaurants.Infrastructure.Authorization
{
    public class RestaurantsUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<User, IdentityRole>
    {
        private readonly UserManager<User> userManager;
        private readonly RoleManager<IdentityRole> roleManager;
        private readonly IOptions<IdentityOptions> options;

        public RestaurantsUserClaimsPrincipalFactory
        (
            UserManager<User> userManager, 
            RoleManager<IdentityRole> roleManager, 
            IOptions<IdentityOptions> options
        ) : base(userManager, roleManager, options)
        {
            this.userManager = userManager;
            this.roleManager = roleManager;
            this.options = options;
        }

        public override async Task<ClaimsPrincipal> CreateAsync(User user)
        {
            var id = await GenerateClaimsAsync(user);
            if (user.Nationality != null)
            {
                id.AddClaim(new Claim("Nationality", user.Nationality));
            }
            if (user.DateOfBirth != null)
            {
                id.AddClaim(new Claim("DateOfBirth", user.DateOfBirth.Value.ToString("yyyy-MM-dd")));
            }
            return new ClaimsPrincipal(id);
        }
    }
}
  1. Restaurants.Infrastructure/Extensions/ServiceCollectionExtensions.cs 里注册自定义的Claim
services.AddIdentityApiEndpoints<User>()
    .AddRoles<IdentityRole>()
    .AddClaimsPrincipalFactory<RestaurantsUserClaimsPrincipalFactory>()
    .AddEntityFrameworkStores<RestaurantsDbContext>();
  1. 如果登录用户这两个属性有值的话,我们就会在token里看到;例如,管理员和owner在创建的时候没有写生日和国籍,普通用户需要在注册的时候写,这是,普通用户的token里,就有了这两个属性;

2.5.2 添加claim属性验证,对国籍进行认证

  1. 添加对国籍进行认证的属性,只有Nationality属性有值的用户才可以访问特定页面
    Restaurants.Infrastructure/Extensions/ServiceCollectionExtensions.cs
services.AddAuthorizationBuilder()
    .AddPolicy("HasNationnality", builder => builder.RequireClaim("Nationality"));
  1. 给指定的controller添加验证

在这里插入图片描述

2.5.3 封装认证的Policy

存在问题:现在认证的属性是hard code直接写成字符串在程序里,需要将他封装起来

  1. 创建Restaurants.Infrastructure/Authorization/Constants.cs用于存放PolicyName认证的名称和认证的字段

namespace Restaurants.Infrastructure.Authorization
{
    //方法名
    public static class PolicyNames
    {
        public const string HasNationality = "HasNationality";
    }
	//字段名
    public static class AppClaimTypes
    {
        public const string Nationality = "Nationality";
        public const string DateOfBirth = "DateOfBirth";
    }
}
  1. 使用封装的名称
services.AddAuthorizationBuilder()
    //.AddPolicy("HasNationnality", builder => builder.RequireClaim("Nationality"));
    .AddPolicy(PolicyNames.HasNationality, builder => builder.RequireClaim(AppClaimTypes.Nationality));

2.5.4 添加对年龄的认证

  1. 在Policy的Constants里添加验证的方法名

2.6 基于资源的授权

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

010 Qt_输入类控件(LineEdit、TextEdit、ComboBox、SpinBox、DateTimeEdit、Dial、Slider)

文章目录 前言一、QLineEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一&#xff1a;用户登录界面5.示例二&#xff1a;验证两次输入的密码是否一致显示密码 二、TextEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一&#xff1a;获取多行输入框的内容5.示例二&#x…

Vue3:uv-upload图片上传

效果图&#xff1a; 参考文档&#xff1a; Upload 上传 | 我的资料管理-uv-ui 是全面兼容vue32、nvue、app、h5、小程序等多端的uni-app生态框架 (uvui.cn) 代码&#xff1a; <view class"greenBtn_zw2" click"handleAddGroup">添加班级群</vie…

通过Docker Compose来实现项目可以指定读取不同环境的yml包

通过Docker Compose来实现项目可以指定读取不同环境的yml包 1. 配置文件2. 启动命令 切换不同环境注意挂载的文件权限要777 1. 配置文件 version: 3.8 services:docker-test:image: openjdk:8-jdk-alpineports:- "${APP_PORT}:${CONTAINER_PORT}"volumes:- "${J…

华为实训课笔记 2024 1223-1224

华为实训 12/2312/24 12/23 [Huawei]stp enable --开启STP display stp brief --查询STP MSTID Port Role STP State Protection 实例ID 端口 端口角色 端口状态 是否开启保护[Huawei]display stp vlan xxxx --查询制定vlan的生成树计算结…

GitCode 光引计划投稿 | GoIoT:开源分布式物联网开发平台

GoIoT 是基于Gin 的开源分布式物联网&#xff08;IoT&#xff09;开发平台&#xff0c;用于快速开发&#xff0c;部署物联设备接入项目&#xff0c;是一套涵盖数据生产、数据使用和数据展示的解决方案。 GoIoT 开发平台&#xff0c;它是一个企业级物联网平台解决方案&#xff…

EasyGBS国标GB28181公网平台P2P远程访问故障诊断:云端服务端排查指南

随着信息技术的飞速发展&#xff0c;视频监控领域正经历从传统安防向智能化、网络化安防的深刻转变。EasyGBS平台&#xff0c;作为基于国标GB28181协议的视频流媒体平台&#xff0c;为用户提供了强大的视频监控直播功能。然而&#xff0c;在实际应用中&#xff0c;P2P远程访问可…

Vnlhun靶场Log4j2漏洞

相关概念 log4j2是Apache的⼀个java日志框架&#xff0c;我们借助它进行日志相关操作管理&#xff0c;然而在2021年末log4j2爆出了远程代码执行漏洞&#xff0c;属于严重等级的漏洞 漏洞原理 简单说就是当你使⽤log4j2中提供的⽅法去输出⽇志信息时&#xff0c;⽐如说最常⻅…

千兆网中的gmii与rgmii

物理链路上是千兆网。1 Gbps1000 Mb/s1000/8 MB/s125 MB/s&#xff0c;这是和你的测试设备相连的1 Gbps物理带宽下的极速。关键点是1 B&#xff08;byte&#xff09;8 b&#xff08;bit&#xff09;。实际下载速度还取决于下载源的限制、出口的物理链路和运营商的限制。

2024-12-24 NO1. XR Interaction ToolKit 环境配置

文章目录 1 软件配置2 安装 XRToolKit3 配置 OpenXR4 安装示例场景5 运行测试 1 软件配置 Unity 版本&#xff1a;Unity6000.0.26 ​ 2 安装 XRToolKit 创建新项目&#xff08;URP 3D&#xff09;&#xff0c;点击进入 Asset Store。 进入“Unity Registry”页签&#xff0…

重温设计模式--外观模式

文章目录 外观模式&#xff08;Facade Pattern&#xff09;概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式&#xff08;Facade Pattern&#xff09;概述 定义 外观模式是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供了一个统一…

【恶意软件检测】一种基于API语义提取的Android恶意软件检测方法(期刊等级:CCF-B、Q2)

一种基于API语义提取的Android恶意软件检测方法 A novel Android malware detection method with API semantics extraction 摘要 由于Android框架和恶意软件的持续演变&#xff0c;使用过时应用程序训练的传统恶意软件检测方法在有效识别复杂演化的恶意软件方面已显不足。为…

【微信小程序】2|轮播图 | 我的咖啡店-综合实训

轮播图 引言 在微信小程序中&#xff0c;轮播图是一种常见的用户界面元素&#xff0c;用于展示广告、产品图片等。本文将通过“我的咖啡店”小程序的轮播图实现&#xff0c;详细介绍如何在微信小程序中创建和管理轮播图。 轮播图数据准备 首先&#xff0c;在home.js文件中&a…

RT-DETR学习笔记(2)

七、IOU-aware query selection 下图是原始DETR。content query 是初始化为0的label embedding, position query 是通过nn.Embedding初始化的一个嵌入矩阵&#xff0c;这两部分没有任何的先验信息&#xff0c;导致DETR的收敛慢。 RT-DETR则提出要给这两部分&#xff08;conten…

fpgafor循环语句使用

genvar i;//循环变量名称 generate for(i0;i<4;ii1)begin:tx//自己定义名称 //循环内容 end endgenerate12位的16进制乘以4就是48位位宽的2进制 因为 222*2(2^4)16

62.基于SpringBoot + Vue实现的前后端分离-驾校预约学习系统(项目+论文)

项目介绍 伴随着信息技术与互联网技术的不断发展&#xff0c;人们进到了一个新的信息化时代&#xff0c;传统管理技术性没法高效率、容易地管理信息内容。为了实现时代的发展必须&#xff0c;提升管理高效率&#xff0c;各种各样管理管理体系应时而生&#xff0c;各个领域陆续进…

网站灰度发布?Tomcat的8005、8009、8080三个端口的作用什么是CDNLVS、Nginx和Haproxy的优缺点服务器无法开机时

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

路由器转发数据报的封装过程

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 路由器转发数据的封装过程 路由器转发数据的封…

webrtc音频模块(三) windows Core Audio API及声音的播放

在前面介绍了ADM(Audio Device Module)&#xff0c;它用于抽象音频设备管理和音频数据采集/播放接口。windows的实现是AudioDeviceWinowCode&#xff0c;它封装了Core Audio APIs实现了对音频设备的操作。 Core Audio APIs windows提供了多种音频操作API&#xff0c;比如最常…

虚拟机桥接模式

主机Win10,虚拟机xp 1.虚拟机设置中选择桥接模式 2.在虚拟机菜单&#xff1a;编辑>虚拟机网络编辑&#xff0c;点击“更改设置”&#xff0c;可以看到三个网卡&#xff0c;这三个网卡分别对应不同的网络共享模式。桥接模式须使用VMnet0&#xff0c;如果没看到这个网卡&…

重温设计模式--享元模式

文章目录 享元模式&#xff08;Flyweight Pattern&#xff09;概述享元模式的结构C 代码示例1应用场景C示例代码2 享元模式&#xff08;Flyweight Pattern&#xff09;概述 定义&#xff1a; 运用共享技术有效地支持大量细粒度的对象。 享元模式是一种结构型设计模式&#xff0…