当前位置: 首页 > news >正文

.NET 8 Web API 中的身份验证和授权

 本次介绍分为3篇文章: 

1:.Net 8 Web API CRUD 操作
.Net 8 Web API CRUD 操作-CSDN博客

2:在 .Net 8 API 中实现 Entity Framework 的 Code First 方法
https://blog.csdn.net/hefeng_aspnet/article/details/143229912

3:.NET 8 Web API 中的身份验证和授权
https://blog.csdn.net/hefeng_aspnet/article/details/143231987 

参考文章:

1:Dot Net 8 Web API CRUD 操作
https://medium.com/@codewithankitsahu/net-8-web-api-crud-operations-125bb3083113

2:在 .Net 8 API 中实现 Entity Framework 的 Code First 方法
https://medium.com/@codewithankitsahu/implement-entity-framework-a-code-first-approach-in-net-8-api-80b06d219373

3:.NET 8 Web API 中的身份验证和授权
https://medium.com/@codewithankitsahu/authentication-and-authorization-in-net-8-web-api-94dda49516ee

介绍

        在本文中,我们将讨论如何在 .NET 8 Web API 中实现身份验证和授权。这是 .Net 8 系列的延续,所以如果你是新手,请查看我之前的文章。

        身份验证和授权代表着根本不同的功能。在本文中,我们将对这两者进行比较和对比,以展示它们如何以互补的方式保护应用程序。

验证

身份验证就是了解用户的身份。 

例如

Alice 使用她的用户名和密码登录,服务器使用该密码对 Alice 进行身份验证。

授权

授权就是决定是否允许用户采取行动。 

例如

Alice 有权限获取资源,但无权创建资源。

让我们开始在我们的应用程序中实现 Jwt Bearer 令牌。

步骤 1.安装 Microsoft.AspNetCore.Authentication.JwtBearer

安装Microsoft.AspNetCore.Authentication.JwtBearer库以在我们的应用程序中实现 JWT 令牌。 

为了这

  • 前往 ne 获取包管理器。
  • 在浏览选项卡中搜索“Microsoft.AspNetCore.Authentication.JwtBearer”。
  • 选择适当的版本,然后单击“安装”按钮。

步骤2.添加Jwt中间件

在我们的应用中添加 Jwt 中间件。为此,请按照以下步骤操作。 

  • 在 API 解决方案中创建 Helpers 文件夹
  • 添加一个名为“JwtMiddleware”的类
  • 添加JwtMiddleware构造函数并在构造函数中注入RequestDelegate和AppSettings。

//JwtMiddleware.cs
using DotNet8WebAPI.Model;
using Microsoft.Extensions.Options;

namespace DotNet8WebAPI.Helpers
{
    public class JwtMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly AppSettings _appSettings;

        public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
        {
            _next = next;
            _appSettings = appSettings.Value;
        }
    }
}

  • 实现Invoke方法
  • 在invoke方法中,从当前请求中读取授权令牌并转发给attachUserToContext方法进行验证,提取用户信息并附加到当前请求。

//JwtMiddleware.cs
using DotNet8WebAPI.Model;
using DotNet8WebAPI.Services;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Text;

namespace DotNet8WebAPI.Helpers
{
public class JwtMiddleware
{
private readonly RequestDelegate _next;
private readonly AppSettings _appSettings;

public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
{
_next = next;
_appSettings = appSettings.Value;
}

public async Task Invoke(HttpContext context, IUserService userService)
{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

if (token != null)
await attachUserToContext(context, userService, token);

await _next(context);
}

private async Task attachUserToContext(HttpContext context, IUserService userService, string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
// set clock skew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);

var jwtToken = (JwtSecurityToken)validatedToken;
var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);

//Attach user to context on successful JWT validation
context.Items["User"] = await userService.GetById(userId);
}
catch
{
//Do nothing if JWT validation fails
// user is not attached to context so the request won't have access to secure routes
}
}
}

  • 将我们的“JwtMiddleware”添加到我们的应用程序中
  • 为此,请转到 Program.cs 并添加它。

app.UseMiddleware<JwtMiddleware>();<JwtMiddleware>(); 

步骤 3.实现 UserService 

实现 UserService。我将帮助注册新用户。 

//IUserService.cs
using DotNet8WebAPI.Model;

namespace DotNet8WebAPI.Services
{
public interface IUserService
{
Task<AuthenticateResponse?> Authenticate(AuthenticateRequest model);
Task<IEnumerable<User>> GetAll();
Task<User?> GetById(int id);
Task<User?> AddAndUpdateUser(User userObj);
}

//UserService.cs
using DotNet8WebAPI.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace DotNet8WebAPI.Services
{
public class UserService : IUserService
{
private readonly AppSettings _appSettings;
private readonly OurHeroDbContext db;

public UserService(IOptions<AppSettings> appSettings, OurHeroDbContext _db)
{
_appSettings = appSettings.Value;
db = _db;
}

public async Task<AuthenticateResponse?> Authenticate(AuthenticateRequest model)
{
var user = await db.Users.SingleOrDefaultAsync(x => x.Username == model.Username && x.Password == model.Password);

// return null if user not found
if (user == null) return null;

// authentication successful so generate jwt token
var token = await generateJwtToken(user);

return new AuthenticateResponse(user, token);
}

public async Task<IEnumerable<User>> GetAll()
{
return await db.Users.Where(x => x.isActive == true).ToListAsync();
}

public async Task<User?> GetById(int id)
{
return await db.Users.FirstOrDefaultAsync(x => x.Id == id);
}

public async Task<User?> AddAndUpdateUser(User userObj)
{
bool isSuccess = false;
if (userObj.Id > 0)
{
var obj = await db.Users.FirstOrDefaultAsync(c => c.Id == userObj.Id);
if (obj != null)
{
// obj.Address = userObj.Address;
obj.FirstName = userObj.FirstName;
obj.LastName = userObj.LastName;
db.Users.Update(obj);
isSuccess = await db.SaveChangesAsync() > 0;
}
}
else
{
await db.Users.AddAsync(userObj);
isSuccess = await db.SaveChangesAsync() > 0;
}

return isSuccess ? userObj: null;
}
// helper methods
private async Task<string> generateJwtToken(User user)
{
//Generate token that is valid for 7 days
var tokenHandler = new JwtSecurityTokenHandler();
var token = await Task.Run(() =>
{

var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
return tokenHandler.CreateToken(tokenDescriptor);
});

return tokenHandler.WriteToken(token);
}
}
}

步骤 4. 添加相应的类模型 

在模型文件夹内添加相应的类模型。

//User.cs
using System.Text.Json.Serialization;

namespace DotNet8WebAPI.Model
{
public class User
{
public int Id { get; set; }
public required string FirstName { get; set; }
public string LastName { get; set; }
public required string Username { get; set; }

[JsonIgnore]
public string Password { get; set; }
public bool isActive { get; set; }
}

//AuthenticateRequest.cs
using System.ComponentModel;

namespace DotNet8WebAPI.Model
{
public class AuthenticateRequest
{
[DefaultValue("System")]
public required string Username { get; set; }

[DefaultValue("System")]
public required string Password { get; set; }
}

//AuthenticateResponse.cs
namespace DotNet8WebAPI.Model
{
public class AuthenticateResponse
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Token { get; set; }


public AuthenticateResponse(User user, string token)
{
Id = user.Id;
FirstName = user.FirstName;
LastName = user.LastName;
Username = user.Username;
Token = token;
}
}

//AppSettings.cs
namespace DotNet8WebAPI.Model
{
public class AppSettings
{
public string Secret { get; set; } = string.Empty;
}

步骤 5. 转到 OurHeroDbContext 文件 

转到 OurHeroDbContext 文件并将用户添加为 DBSet。

public DbSet<User> Users { get; set; } 

//OurHeroDbContext.cs
using DotNet8WebAPI.Model;
using Microsoft.EntityFrameworkCore;

namespace DotNet8WebAPI
{
public class OurHeroDbContext : DbContext
{
public OurHeroDbContext(DbContextOptions<OurHeroDbContext> options) : base(options)
{
}

public DbSet<OurHero> OurHeros { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OurHero>().HasKey(x => x.Id);

modelBuilder.Entity<OurHero>().HasData(
new OurHero
{
Id = 1,
FirstName = "System",
LastName = "",
isActive = true,
}
);

modelBuilder.Entity<User>().HasData(
new User
{
Id = 1,
FirstName = "System",
LastName = "",
Username = "System",
Password = "System",
}
);
}

}

步骤 6.添加 JWT 密钥 

在应用程序设置文件中添加 JWT Secret。

"AppSettings": {
"Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
}, 

//appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AppSettings": {
"Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
},
"ConnectionStrings": {
"OurHeroConnectionString": "Data Source=LAPTOP-4TSM9SDC;Initial Catalog=OurHeroDB; Integrated Security=true;TrustServerCertificate=True;"
},
"AllowedHosts": "*"

步骤 7.注册 AppSettings 和 UserServices

在应用程序中注册AppSettings和UserServices。

转到 Program.cs 文件并注册我们的服务。

//Program.cs
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
builder.Services.AddScoped<IUserService, UserService>(); 

步骤 8. 运行以下命令

运行以下命令来添加迁移并更新数据库。 

  • 运行add-migration [名称]
  • 更新数据库

步骤 9.实现 AuthorizeAttribute

实现 AuthorizeAttribute 来保护我们并指向匿名用途。 

  • Helpers文件夹中添加AuthorizeAttribute类。
  • 此类与AttributeIAuthorizationFilter 的关联范围。
  • 实现 OnAuthorization 方法。

//AuthorizeAttribute.cs
using DotNet8WebAPI.Model;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;

namespace DotNet8WebAPI.Helpers
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var user = (User?)context.HttpContext.Items["User"];
            if (user == null)
            {
                context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
            }
        }
    }
}

步骤 10. 应用 AuthorizeAttribute

根据您的需求,在控制器级别或 Action 方法级别应用AuthorizeAttribute 。 

using DotNet8WebAPI.Helpers;
using DotNet8WebAPI.Model;
using DotNet8WebAPI.Services;
using Microsoft.AspNetCore.Mvc;

namespace DotNet8WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController] // Controller level
    [Authorize]
    public class OurHeroController : ControllerBase
    {
        private readonly IOurHeroService _heroService;
        public OurHeroController(IOurHeroService heroService)
        {
            _heroService = heroService;
        }

        //[ApiController]  // Action method level
        [HttpGet]
        public async Task<IActionResult> Get([FromQuery] bool? isActive = null)
        {
            var heros = await _heroService.GetAllHeros(isActive);
            return Ok(heros);
        }

        [HttpGet("{id}")]
        //[Route("{id}")] // /api/OurHero/:id
        public async Task<IActionResult> Get(int id)
        {
            var hero = await _heroService.GetHerosByID(id);
            if (hero == null)
            {
                return NotFound();
            }
            return Ok(hero);
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] AddUpdateOurHero heroObject)
        {
            var hero = await _heroService.AddOurHero(heroObject);

            if (hero == null)
            {
                return BadRequest();
            }

            return Ok(new
            {
                message = "Super Hero Created Successfully!!!",
                id = hero!.Id
            });
        }

        [HttpPut]
        [Route("{id}")]
        public async Task<IActionResult> Put([FromRoute] int id, [FromBody] AddUpdateOurHero heroObject)
        {
            var hero = await _heroService.UpdateOurHero(id, heroObject);
            if (hero == null)
            {
                return NotFound();
            }

            return Ok(new
            {
                message = "Super Hero Updated Successfully!!!",
                id = hero!.Id
            });
        }

        [HttpDelete]
        [Route("{id}")]
        public async Task<IActionResult> Delete([FromRoute] int id)
        {
            if (!await _heroService.DeleteHerosByID(id))
            {
                return NotFound();
            }

            return Ok(new
            {
                message = "Super Hero Deleted Successfully!!!",
                id = id
            });
        }
    }
}

//UsersController.cs
using DotNet8WebAPI.Helpers;
using DotNet8WebAPI.Model;
using DotNet8WebAPI.Services;
using Microsoft.AspNetCore.Mvc;

namespace DotNet8WebAPI.Controllers
{
    [Route("api/[controller]")] //    /api/Users
    [ApiController]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [HttpPost("authenticate")]
        public async Task<IActionResult> Authenticate(AuthenticateRequest model)
        {
            var response = await _userService.Authenticate(model);

            if (response == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(response);
        }

        // POST api/<CustomerController>
        [HttpPost]
        [Authorize]
        public async Task<IActionResult> Post([FromBody] User userObj)
        {
            userObj.Id = 0;
            return Ok(await _userService.AddAndUpdateUser(userObj));
        }

        // PUT api/<CustomerController>/5
        [HttpPut("{id}")]
        [Authorize]
        public async Task<IActionResult> Put(int id, [FromBody] User userObj)
        {
            return Ok(await _userService.AddAndUpdateUser(userObj));
        }
    }
}

步骤11.API安全性

现在我们的 API 对于未经身份验证的用户来说是安全的。 

但是如果您想使用 Swagger 测试我们的 API,那么我们需要接受 Bearer 令牌。

转到 Program.cs 文件并实现它。

builder.Services.AddSwaggerGen(swagger =>Services.AddSwaggerGen(swagger =>
{
    //This is to generate the Default UI of Swagger Documentation
    swagger.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "JWT Token Authentication API",
        Description = ".NET 8 Web API"
    });
    // To Enable authorization using Swagger (JWT)
    swagger.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {
        Name = "Authorization",
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer",
        BearerFormat = "JWT",
        In = ParameterLocation.Header,
        Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"",
    });
    swagger.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                          new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference
                                {
                                    Type = ReferenceType.SecurityScheme,
                                    Id = "Bearer"
                                }
                            },
                            new string[] {}

                    }
                });
});

步骤 12. 运行 Web API 

运行 Web API(按 F5)并调用“/api/Users/authenticate” API。 

步骤 13.复制 JWT 令牌 

  • 单击授权按钮,并在值部分提供令牌“ Bearer <token> ”。
  • 然后点击授权按钮来验证 Web API。

步骤 14. 调用“/api/OurHero” API

现在,如果您调用“/api/OurHero” API,它将起作用,但如果没有 JWT 令牌,它将抛出401(未授权)错误。 

  • 使用 JWT 令牌 — 工作正常。

没有 JWT 令牌 — 抛出401错误。 

概括

        就这样!您已经创建了一个完整的 .NET 8 Web API,用于使用内存数据库和 JWT 身份验证进行 CRUD 操作。您现在可以将此 API 集成到您的前端应用程序中。 

相关文章:

.NET 8 Web API 中的身份验证和授权

本次介绍分为3篇文章&#xff1a; 1&#xff1a;.Net 8 Web API CRUD 操作.Net 8 Web API CRUD 操作-CSDN博客 2&#xff1a;在 .Net 8 API 中实现 Entity Framework 的 Code First 方法https://blog.csdn.net/hefeng_aspnet/article/details/143229912 3&#xff1a;.NET …...

Vue弹窗用也可以直接调用Js方法了

问题描述 在前端开发中&#xff0c;弹窗开发是一个不可避免的场景。然而&#xff0c;按照正常的逻辑&#xff0c;通过在template模板中先引用组件&#xff0c;然后通过v-if指令控制显隐&#xff0c;进而达到弹窗的效果。然而&#xff0c;这种方法却有一个严重的缺陷&#xff0…...

【c语言测试】

1. C语言中&#xff0c;逻辑“真”等价于&#xff08; &#xff09; 题目分析&#xff1a; “逻辑真”在C语言中通常指的是非零数。 A. 大于零的数B. 大于零的整数C. 非零的数 (正确答案)D. 非零的整数 正确答案&#xff1a;C 2. 若定义了数组 int a[3][4];&#xff0c;则对…...

一种将树莓派打造为游戏机的方法——Lakka

什么是Lakka&#xff1f; Lakka是一款Linux发行版&#xff0c;轻量级的&#xff0c;可将小型计算机转变为一台复古游戏机。 图1-Lakka官网&#xff0c;见参考链接[1] Lakka是RetroArch和libretro生态系统下的官方操作系统&#xff0c;前者RetroArch是模拟器、游戏引擎和媒体播…...

如何在 MySQL 中创建一个完整的数据库备份?

在MySQL数据库中创建一个完整的数据库备份通常不是通过编程语言直接实现的&#xff0c;而是借助MySQL提供的命令行工具mysqldump来完成。 作为Java开发者&#xff0c;我们可以编写脚本来调用这些工具&#xff0c;从而实现自动化备份。 下面我们将详细介绍如何使用Java来调度m…...

京准电钟HR-901GB双GPS北斗卫星时钟服务器

京准电钟HR-901GB双GPS北斗卫星时钟服务器 京准电钟HR-901GB双GPS北斗卫星时钟服务器 作为国家电力系统最重要的设备之一,卫星时间同步装置随着电力行业的发展不断有了新的要求,从单纯的具备时间数据输出能力,发展到装置状态信息上送、对用时设备的对时质量进行监测,确保站点内…...

uniapp使用websocket

后端java websoket中的 onOpen 中。依赖注入为null 引用&#xff1a;https://blog.csdn.net/qq_63431773/article/details/132389555 https://blog.csdn.net/weixin_43961117/article/details/123989515 https://cloud.tencent.com/developer/article/2107954 https://blog.c…...

基于Pycharm和Django模型技术的数据迁移

1.配置数据库 在trip_server/settings.py中修改配置&#xff1a; 其格式可访问官网&#xff1a;Settings | Django documentation | Django 1.1 配置数据库 文件地址&#xff1a;trip_server/settings.py 配置前需要创建&#xff08;NaviCat&#xff09;个人数据库 "…...

乐尚代驾-----Day10(订单三)

hi UU 们&#xff01;&#xff01;&#xff01;我又来跟辛辣&#xff01;感谢你们的观看&#xff0c;话不多说&#xff01;~ 司机到达代驾终点&#xff0c;代驾结束了。结束代驾之后&#xff0c; – 获取额外费用&#xff08;高速费、停车费等&#xff09; – 计算订单实际里程…...

105. 聚光源SpotLight

入门部分给大家介绍过平行光DirectionalLight、点光源PointLight、环境光AmbientLight,下面给大家介绍一个新的光源对象&#xff0c;也就是聚光源SpotLight。 创建聚光源SpotLight 聚光源可以认为是一个沿着特定方会逐渐发散的光源&#xff0c;照射范围在三维空间中构成一个圆…...

系统接口权限拦截器,获取用户信息存储

UserInfo 类 这是一个表示用户信息的 Java 类&#xff0c;使用了 Lombok 注解来简化代码编写。 import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString;import java.io.Serializable; import java.util.List;Data ToString EqualsAndHashCode public…...

Chromium HTML5 新的 Input 类型color 对应c++

一、Input 类型: color color 类型用在input字段主要用于选取颜色&#xff0c;如下所示&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body&…...

问:SQL中的通用函数及用法?

SQL函数是在SQL语句中使用的预定义的计算工具&#xff0c;可以对一列数据进行操作并返回一个单一的结果。这些函数大致可以分为两类&#xff1a;Aggregate函数和Scalar函数。Aggregate函数对一组值执行计算&#xff0c;并返回单个值&#xff0c;如求和、平均值、最大值和最小值…...

.NET Core WebApi第6讲:WebApi的前端怎么派人去拿数据?(区别MVC)

一、前端界面小基础 head&#xff1a;引入CSS, 引入JS是写在head里面。 body&#xff1a;眼睛肉眼能看到的用户展示的界面是写在body里面。 二、前端怎么派人去拿数据&#xff1f; 1、MVC&#xff1a;前后端不分离&#xff0c;MVC相比WebApi只是多了一个views的文件夹 &am…...

Chromium HTML5 新的 Input 类型date 对应c++

一、Input 类型: date date 类型允许你从一个日期选择器选择一个日期。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body><form action"demo-form.php"…...

ZooKeeper的应用场景:深入探讨分布式系统中的多样化应用

Apache ZooKeeper 是一个开源的分布式协调服务&#xff0c;专为确保分布式系统中的高可用性和一致性而设计。在现代分布式应用程序中&#xff0c;协调、同步和管理是实现高效和可靠服务的关键部分&#xff0c;而 ZooKeeper 通过提供这些基础功能而成为许多分布式系统不可或缺的…...

【Vue3】第四篇

Vue3学习第四篇 01. 插槽Slots02. 插槽Slots&#xff08;续集&#xff09;03. 插槽Slots&#xff08;再续集&#xff09;04. 组件生命周期05. 生命周期应用06. 动态组件07. 组件保持存活08. 异步组件09. 依赖注入10. Vue应用 01. 插槽Slots 模板内容&#xff1a;html结构&#…...

Chromium HTML5 新的 Input 类型tel对应c++

一、Input 类型: tel <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body><form action"demo-form.php">电话号码: <input type"tel" name…...

JVM—类加载器、双亲委派机制

目录 什么是类加载器 类加载器的分类 Bootstrap启动类加载器 通过启动类加载器加载用户jar包 Extension扩展类加载器和Application应用程序类加载器 通过扩展类加载器加载用户jar包 双亲委派机制 打破双亲委派机制 自定义类加载器 线程上下文类加载器 Osgi框架的类加…...

笔试题 求空格分割的英文句子中,最大单词长度。

求空格分割的英文句子中&#xff0c;最大单词长度。例如:“this is a word”&#xff0c;最大单词长度为4。要求:不能用 split 函数对字符串进行切分&#xff0c;算法复杂度为o(n) public class MaxWordLength { public static int maxWordLength(String sentence) { if (se…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...