当前位置: 首页 > 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…...

Pixel Fashion Atelier基础教程:硬核8-Bit界面操作逻辑与非对称布局解析

Pixel Fashion Atelier基础教程&#xff1a;硬核8-Bit界面操作逻辑与非对称布局解析 1. 像素时装锻造坊简介 Pixel Fashion Atelier是一款基于Stable Diffusion与Anything-v5的图像生成工具&#xff0c;它彻底改变了传统AI工具的界面设计理念。这款工具将复古日系RPG的"…...

RWKV7-1.5B-g1a一文详解:轻量中文对话与文案续写实战

RWKV7-1.5B-g1a一文详解&#xff1a;轻量中文对话与文案续写实战 1. 模型简介 rwkv7-1.5B-g1a 是一款基于RWKV-7架构的多语言文本生成模型&#xff0c;特别适合中文场景下的轻量级应用。这个1.5B参数的模型在保持较小体积的同时&#xff0c;能够出色完成基础问答、文案续写、简…...

Image-to-Video镜像使用技巧:提示词怎么写?参数怎么调?

Image-to-Video镜像使用技巧&#xff1a;提示词怎么写&#xff1f;参数怎么调&#xff1f; 1. 快速上手Image-to-Video镜像 Image-to-Video图像转视频生成器是一款基于I2VGen-XL模型的实用工具&#xff0c;能够将静态图片转化为动态视频。这个由科哥二次开发的镜像已经预装了…...

PyTorch 2.8镜像保姆级教程:RTX 4090D下模型量化工具AutoGPTQ实操

PyTorch 2.8镜像保姆级教程&#xff1a;RTX 4090D下模型量化工具AutoGPTQ实操 1. 环境准备与快速部署 在开始使用AutoGPTQ进行模型量化之前&#xff0c;我们需要确保PyTorch 2.8镜像环境已经正确部署。本镜像专为RTX 4090D 24GB显卡优化&#xff0c;预装了CUDA 12.4和所有必要…...

Llama-3.2V-11B-cot在智能教育中的应用:数学题配图逻辑漏洞识别实战

Llama-3.2V-11B-cot在智能教育中的应用&#xff1a;数学题配图逻辑漏洞识别实战 1. 引言&#xff1a;当AI遇见数学教育 数学教材和习题集中的配图错误是一个长期困扰教育行业的难题。据统计&#xff0c;约15%的数学教材配图存在不同程度的逻辑漏洞或表达偏差&#xff0c;这些…...

从反射率到耐候性:5个关键参数教你像专业人士一样测试LED封装胶水

从反射率到耐候性&#xff1a;5个关键参数教你像专业人士一样测试LED封装胶水 在LED制造领域&#xff0c;封装胶水就像光学系统的"隐形工程师"&#xff0c;它不仅要牢固固定芯片和荧光粉&#xff0c;更承担着光线管理的关键任务。一款优质的高反射率封装胶水&#xf…...

DoL-Lyra构建系统:5分钟学会自动化游戏MOD打包

DoL-Lyra构建系统&#xff1a;5分钟学会自动化游戏MOD打包 【免费下载链接】DOL-CHS-MODS Degrees of Lewdity 整合 项目地址: https://gitcode.com/gh_mirrors/do/DOL-CHS-MODS DOL-CHS-MODS&#xff08;Degrees of Lewdity汉化美化整合包&#xff09;是一款专为Degree…...

17:L关注AI伦理:蓝队的道德防御

作者&#xff1a; HOS(安全风信子) 日期&#xff1a; 2026-03-17 主要来源平台&#xff1a; GitHub 摘要&#xff1a; 当基拉开始利用AI的伦理漏洞时&#xff0c;传统的安全防御已无法应对。L将AI伦理原则融入安全防御&#xff0c;构建符合道德规范的安全体系。本文拆解L如何在…...

EmbeddingGemma-300m在Mathtype公式的语义理解中的应用

EmbeddingGemma-300m在Mathtype公式的语义理解中的应用 1. 引言 数学公式的语义理解一直是自然语言处理领域的挑战性任务。传统的文本嵌入模型在处理复杂的数学表达式时往往力不从心&#xff0c;无法准确捕捉公式背后的数学含义和逻辑关系。EmbeddingGemma-300m作为Google最新…...

OpenClaw成本优化方案:ollama GLM-4.7-Flash自建模型接口实践

OpenClaw成本优化方案&#xff1a;ollama GLM-4.7-Flash自建模型接口实践 1. 为什么需要关注OpenClaw的token消耗问题 第一次用OpenClaw完成自动化周报任务时&#xff0c;我盯着账单倒吸一口凉气——生成三份周报竟然消耗了接近15万token。这让我意识到&#xff0c;如果不解决…...