.NET 6.0 WebAPI 使用JWT生成Token的验证授权

news2024/11/15 15:50:16

1.引入相关程序包JwtBearer注意版本:

2.配置文件appsettings.json写相关配置参数(也可不写,写在程序里面,数据库读取也是一样的)

, //JWT加密
  "JWTToken": {
    "SecretKey": "jsaduwqe6asdjewejdue7dfmsdfu0sdfmwmsd8wfsd6", //密钥
    "Issuer": "ZYP", //发行者
    "Audience": "simple", //拥护者
    //"ExpireMinutes": 240 //过期时间
  }

3.在Program配置相关服务。

#region JWT
//获取配置文件
var configuration = builder.Configuration;
string Issuer = configuration["JWTToken:Issuer"];
string Audience = configuration["JWTToken:Audience"];
string SecretKey = configuration["JWTToken:SecretKey"];
//注入jwt
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        //过期时间容错值,解决服务器端时间不同步问题(秒)
        //允许服务器时间偏移量30秒,即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 + 偏移值)你也可以设置为0,ClockSkew = TimeSpan.Zero
        ClockSkew = TimeSpan.FromSeconds(30),
        //要求Token的Claims中必须包含Expires
        RequireExpirationTime = true,
        //是否在令牌期间验证签发者
        ValidateIssuer = true,
        //发行人Issuer
        ValidIssuer = Issuer, 
        //是否验证接收者
        ValidateAudience = true,
        //是否验证失效时间
        ValidateLifetime = true,
        //是否验证签名SecurityKey
        ValidateIssuerSigningKey = true,
        //接收者
        ValidAudience = Audience,
        //密钥SecurityKey
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey)), 
    };
});
//注入JwtHelper
builder.Services.AddSingleton(new JwtHelper(configuration));
#endregion

//注入Swagger,注入这个才能在调试接口时输入token
builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference=new OpenApiReference{Id="Bearer",Type=ReferenceType.SecurityScheme},
            },
            Array.Empty<string>()
        }
    });

    options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
    {
        Description = "请输入文字'Bearer '后面跟空格和token格式  Bearer {token}",
        Name = "Authorization",
        In = Microsoft.OpenApi.Models.ParameterLocation.Header,
        Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey
    });
});

//配置跨域
builder.Services.AddCors(policy =>
{
    policy.AddPolicy("CorsPolicy", opt => opt
    .AllowAnyOrigin()
    .AllowAnyHeader()
    .AllowAnyMethod()
    .WithExposedHeaders("X-Pagination"));
});

//调用中间件:UseAuthentication(认证),
//必须在所有需要身份认证的中间件前调用,比如 UseAuthorization(授权)。
app.UseAuthentication();
//调用中间件:UseAuthorization(授权)。
app.UseAuthorization();

4.相关配置结束后,我们得生成Token,这时我们创建一个专门生成Token的类里面有两个生成Token的方法,想用哪个用哪个。该类在Program里有引用。

 /// <summary>
 /// Token生成类
 /// </summary>
 public class JwtHelper
 {
     /// <summary>
     /// 配置文件信息
     /// </summary>
     private readonly IConfiguration _configuration;
     public JwtHelper(IConfiguration configuration)
     {
         _configuration = configuration;
     }

     /// <summary>
     /// 创建一个使用控制器方法授权的Token
     /// </summary>
     /// <returns></returns>
     public string CreatePermissionToken(string UserName, string RoleName, string AppId, Claim[] claims)
     {
         // 1. 定义需要使用到的Claims
         if (claims == null)
         {
             claims = new[]
             {
                 new Claim(ClaimTypes.Name, UserName), //HttpContext.User.Identity.Name
                 new Claim(ClaimTypes.Role, RoleName), //HttpContext.User.IsInRole("r_admin")
                 new Claim(JwtRegisteredClaimNames.Jti, AppId),//分配给订阅着的特定Id
                 new Claim("Permission", Permissions.UserCreate),
                 new Claim("Permission", Permissions.UserDelete),
                 new Claim("Permission", Permissions.UserUpdate),
                 new Claim("Permission", Permissions.UserSelect)
                 //new Claim("Username", "Admin"),//其他荷载信息
             };
         }
         // 2. 从 appsettings.json 中读取密钥SecretKey
         var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWTToken:SecretKey"]));

         // 3. 选择加密算法
         var algorithm = SecurityAlgorithms.HmacSha256;

         // 4. 生成Credentials
         var signingCredentials = new SigningCredentials(secretKey, algorithm);

         // 5. 根据以上,生成token
         var Token = new JwtSecurityToken(
             issuer: _configuration["JWTToken:Issuer"], //发布者
             audience: _configuration["JWTToken:Audience"], //接收者
             claims: claims, //存放的用户信息
             notBefore: DateTime.Now, //发布时间
             expires: System.DateTime.Now.AddHours(48), //有效期设置为48小时
             signingCredentials: signingCredentials //数字签名,用于生成Token的Header,其余都是荷载数据
             );
         // 6. 将token变为string
         var token = new JwtSecurityTokenHandler().WriteToken(Token);
         return token;
     }

     /// <summary>
     /// 创建一个使用账号密码授权验证的Token
     /// </summary>
     /// <param name="UserName"></param>
     /// <param name="RoleName"></param>
     /// <param name="AppId"></param>
     /// <param name="Account"></param>
     /// <param name="PassWord"></param>
     /// <returns></returns>
     public string CreateLoginToken(string UserName, string RoleName, string AppId, string Account, string PassWord)
     {
         // 1. 定义需要使用到的Claims
         var claims = new[]
         {
             new Claim(ClaimTypes.Name, UserName),
             new Claim(ClaimTypes.Role, RoleName),
             new Claim(JwtRegisteredClaimNames.Jti, AppId),//分配给订阅着的特定Id
             new Claim("Account", Account),//账号
             new Claim("PassWord", PassWord)//密码,可以要求使用特定加密技术加密
             //new Claim("Username", "Admin"),//其他荷载信息
         };

         // 2. 从 appsettings.json 中读取密钥SecretKey
         var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWTToken:SecretKey"]));

         // 3. 选择加密算法
         var algorithm = SecurityAlgorithms.HmacSha256;

         // 4. 生成Credentials
         var signingCredentials = new SigningCredentials(secretKey, algorithm);

         // 5. 根据以上,生成token
         var Token = new JwtSecurityToken(
             issuer: _configuration["JWTToken:Issuer"], //发布者
             audience: _configuration["JWTToken:Audience"], //接收者
             claims: claims, //存放的用户信息
             notBefore: DateTime.Now, //发布时间
             expires: System.DateTime.Now.AddHours(48), //有效期设置为48小时
             signingCredentials: signingCredentials //数字签名,用于生成Token的Header,其余都是荷载数据
             );
         // 6. 将token变为string
         var token = new JwtSecurityTokenHandler().WriteToken(Token);
         return token;
     }
 }

5.这时可以生成Token了,我们来新建一个控制器来生成一个试试:

[Route("api/[controller]")]
[ApiController]
public class GetTokenController : ControllerBase
{
    private readonly JwtHelper _jwtHelper;
    public GetTokenController(JwtHelper jwtHelper)
    {
        _jwtHelper = jwtHelper;
    }
    [HttpPost]
    [Route("Token")]
    public Task<JsonResult> GetToken(UserToken token)
    {
        string thetoken =  _jwtHelper.CreateLoginToken(token.Name, "User", token.AppId, token.Account, token.PassWord);
        var result = new
        {
            success = true,
            msg = "OK",//消息
            token = thetoken
        };
        return Task.FromResult(new JsonResult(result));
    }
}

控制器的参数类(根据自己需要修改) 

public class UserToken
{
    /// <summary>
    /// 给需要访问本系统的程序的唯一标识
    /// </summary>
    public string AppId { get; set; } = string.Empty;
    /// <summary>
    /// 需要访问本系统的程序的名称
    /// </summary>
    public string Name { get; set; } = string.Empty;
    /// <summary>
    /// 分配给需要访问本系统的程序的账号
    /// </summary>
    public string Account { get; set; } = string.Empty;
    /// <summary>
    /// 分配给需要访问本系统的程序的密码
    /// </summary>
    public string PassWord { get; set; } = string.Empty;
}

启动程序测试,生成成功!:

6.既然可以生成Token了,那么就该给控制器授权了,总不能让每个携带Token的用户能访问系统所以的API吧,那样会出现垂直越权的情况,渗透测试过不了哦。

相关标签:Authorize 和 AllowAnonymous

授权方式:介绍三种授权方式(Policy、Role、Scheme)

此处着重说Policy方式,对Role方法感兴趣的可以看我前面的Cookie方式验证。

6.1首先新建一个JwtAuthorizationRequirement类(类名不固定)用于继承IAuthorizationRequirement

public class JwtAuthorizationRequirement : IAuthorizationRequirement
{
    //这里可以扩展一些其他的角色或者需要的东西.
    //txt参数是在使用策略授权时传入进来的,例如:Authorize(Policy= "MyPolicy")的MyPolicy
    public JwtAuthorizationRequirement(string name)
    {
        Name = name;
    }
    public string? Name { get; set; }
}

 6.2然后新建一个JwtAuthorizationHandler类继承AuthorizationHandler<JwtAuthorizationRequirement>

/// <summary>
/// 检验策略,相当于.NET MVC继承AuthorizeAttribute实现JWT的拦截器的效果。
/// </summary>
public class JwtAuthorizationHandler : AuthorizationHandler<JwtAuthorizationRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, JwtAuthorizationRequirement requirement)
    {
        if (context.User == null)
        {
            context.Fail();
            return Task.CompletedTask;
        }
        //requirement.Name 就是在添加策略授权时传入的值 
        string? Account = context.User.Claims.FirstOrDefault(p => p.Type == requirement.Name)?.Value;
        string? PassWord = context.User.Claims.FirstOrDefault(p => p.Type == "PassWord")?.Value;
        //这里时数据库或者其他方式校验 
        if (Account=="1234")
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
        return Task.CompletedTask;
    }
}

6.3然后将该策略在Program下注入

//注入授权策略(非必要,仅有需要自定义授权规则时使用)
builder.Services.AddSingleton<IAuthorizationHandler, JwtAuthorizationHandler>();
//账号密码验证策略
builder.Services.AddAuthorization(p =>
{
    p.AddPolicy("Account", t =>
    {
        t.Requirements.Add(new JwtAuthorizationRequirement("Account"));
    });
});

6.4 使用:

 [Authorize(policy: "Account")]//主要是这个
 public IEnumerable<WeatherForecast> Get()
 {
     return Enumerable.Range(1, 5).Select(index => new WeatherForecast
     {
         Date = DateTime.Now.AddDays(index),
         TemperatureC = Random.Shared.Next(-20, 55),
         Summary = Summaries[Random.Shared.Next(Summaries.Length)]
     })
     .ToArray();
 }

策略授权基本就是这样了。

再贴一个策略授权代码(可以忽略):

  /// <summary>
  /// 规则授权参数
  /// </summary>
  public class Permissions
  {
      /// <summary>
      /// 规则受体
      /// </summary>
      public const string User = "User";
      /// <summary>
      /// 增权限
      /// </summary>
      public const string UserCreate = User + ".Create";
      /// <summary>
      /// 删权限
      /// </summary>
      public const string UserDelete = User + ".Delete";
      /// <summary>
      /// 改权限
      /// </summary>
      public const string UserUpdate = User + ".Update";
      /// <summary>
      /// 查权限
      /// </summary>
      public const string UserSelect = User + ".Select";
  }

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    /// <summary>
    /// 参数是在使用策略授权时传入进来的,例如:Authorize(Policy= "MyPolicy")的MyPolicy
    /// </summary>
    /// <param name="name">Authorize(Policy= "MyPolicy")的MyPolicy</param>
    public PermissionAuthorizationRequirement(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
}
    public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
        {
            //取出当前用户的所有Permission的参数
            var permissions = context.User.Claims.Where(_ => _.Type == "Permission").Select(_ => _.Value).ToList();
            //是否满足授权,满足则运行 context.Succeed 
            if (permissions.Any(_ => _.StartsWith(requirement.Name)))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
            return Task.CompletedTask;
        }
    }

Program

builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
//控制器方法验证策略
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(Permissions.UserCreate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserCreate)));
    options.AddPolicy(Permissions.UserUpdate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserUpdate)));
    options.AddPolicy(Permissions.UserDelete, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserDelete)));
    options.AddPolicy(Permissions.UserSelect, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserSelect)));
});

7.最后.整个Program

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//首先引用Microsoft.AspNetCore.Mvc.NewtonsoftJson包。再在builder.Services.AddControllers()后添加相应内容
builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
    //设置JSON返回数据格式大小写与Model一致
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    //设置一般API的日期格式
    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
});

#region JWT
//获取配置文件
var configuration = builder.Configuration;
string Issuer = configuration["JWTToken:Issuer"];
string Audience = configuration["JWTToken:Audience"];
string SecretKey = configuration["JWTToken:SecretKey"];
//注入jwt
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        //过期时间容错值,解决服务器端时间不同步问题(秒)
        //允许服务器时间偏移量30秒,即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 + 偏移值)你也可以设置为0,ClockSkew = TimeSpan.Zero
        ClockSkew = TimeSpan.FromSeconds(30),
        //要求Token的Claims中必须包含Expires
        RequireExpirationTime = true,
        //是否在令牌期间验证签发者
        ValidateIssuer = true,
        //发行人Issuer
        ValidIssuer = Issuer, 
        //是否验证接收者
        ValidateAudience = true,
        //是否验证失效时间
        ValidateLifetime = true,
        //是否验证签名SecurityKey
        ValidateIssuerSigningKey = true,
        //接收者
        ValidAudience = Audience,
        //密钥SecurityKey
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey)), 
    };
});
//注入JwtHelper
builder.Services.AddSingleton(new JwtHelper(configuration));
//注入授权策略(非必要,仅有需要自定义授权规则时使用)
builder.Services.AddSingleton<IAuthorizationHandler, JwtAuthorizationHandler>();
//账号密码验证策略
builder.Services.AddAuthorization(p =>
{
    p.AddPolicy("Account", t =>
    {
        t.Requirements.Add(new JwtAuthorizationRequirement("Account"));
    });
});

builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
//控制器方法验证策略
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(Permissions.UserCreate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserCreate)));
    options.AddPolicy(Permissions.UserUpdate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserUpdate)));
    options.AddPolicy(Permissions.UserDelete, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserDelete)));
    options.AddPolicy(Permissions.UserSelect, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(Permissions.UserSelect)));
});
#endregion
//注入Swagger
builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference=new OpenApiReference{Id="Bearer",Type=ReferenceType.SecurityScheme},
            },
            Array.Empty<string>()
        }
    });

    options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
    {
        Description = "请输入文字'Bearer '后面跟空格和token格式  Bearer {token}",
        Name = "Authorization",
        In = Microsoft.OpenApi.Models.ParameterLocation.Header,
        Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey
    });
});

//配置跨域
builder.Services.AddCors(policy =>
{
    policy.AddPolicy("CorsPolicy", opt => opt
    .AllowAnyOrigin()
    .AllowAnyHeader()
    .AllowAnyMethod()
    .WithExposedHeaders("X-Pagination"));
});
var app = builder.Build();
//调用中间件:UseAuthentication(认证),
//必须在所有需要身份认证的中间件前调用,比如 UseAuthorization(授权)。
app.UseAuthentication();
//调用中间件:UseAuthorization(授权)。
app.UseAuthorization();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapControllers();

app.Run();

参考链接:ASP.NET Core 6.0 添加 JWT 认证和授权 - 芦荟柚子茶 - 博客园

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

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

相关文章

洛谷-P3916 图的遍历

题目描述 给出 N 个点&#xff0c;M 条边的有向图&#xff0c;对于每个点 v&#xff0c;求A(v) 表示从点 v 出发&#xff0c;能到达编号最大的点。 思路 既然是要找到最大的点&#xff0c;那么我从最大的点开始DFS是否可以&#xff1f; 于是可以反向建图&#xff0c;然后从最…

HTML图片标记(四)配图详解

目录 1.HTML图片的基础语法 2.设置图片大小 3.改变图片边距 4.图片对齐方式 1.HTML图片的基础语法 <img src"图片路径"> 2.设置图片大小 <img src"图片路径" width"" length""> 3.改变图片边距 <img src"…

Python 二次开发金橙子打印软件:开启高效打印新旅程

目录 一、准备工作&#xff1a;搭建系统环境 二、二次开发流程详解 结合一个实例来讲解如何进行二次开发。 三、Python 二次开发关键要素 &#xff08;一&#xff09;源码示例与解读 &#xff08;二&#xff09;二次开发文档指引 四、问题汇总与解决方案 &#xff08;一…

【HTML5】html5开篇基础(2)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

Spring Boot 学习之路 -- 配置项目

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精通&…

【一起学NLP】Chapter2-学习神经网络

目录 学习神经网络损失函数Tip:One-hot向量导数与梯度Tip:严格地说链式法则计算图反向传播其他典型的运算结点乘法结点分支节点Repeat节点Sum节点MatMul节点 Tip:浅拷贝和深拷贝的差异梯度的推导和反向传播的实现Sigmoid层Affine层Softmax with Loss层 权重的更新——随机梯度下…

[PICO VR]Unity如何往PICO VR眼镜里写持久化数据txt/json文本

前言 最近在用PICO VR做用户实验&#xff0c;需要将用户实验的数据记录到PICO头盔的存储空间里&#xff0c;记录一下整个过程 流程 1.开启写入权限 首先开启写入权限&#xff1a;Unity->Edit->Player->安卓小机器人->Other Settings->Configuration->Wri…

大数据毕业设计选题推荐-网络电视剧收视率分析系统-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

数据库主备副本物理复制和逻辑复制对比

数据库主从节点的数据一致性是保证数据库高可用的基本要求&#xff0c;各个数据库在实现方式上也各有异同。而主备复制的方式无外乎两种&#xff1a;物理复制和逻辑复制&#xff0c;本文简要对比下两种方式的不同&#xff0c;并分析下国产数据库是如何实现的。 1、数据库复制基…

中国中车在线测评考的啥?大易题库如何通过|附真题型国企题库通关秘籍和攻略

言语理解题目&#xff1a;这类题目主要考察你的语言理解和表达能力&#xff0c;例如&#xff0c;给你一个段落&#xff0c;让你根据段落内容选择最合适的答案。要点是快速捕捉文段中的关键信息&#xff0c;理解作者的意图和观点 逻辑推理题目&#xff1a;这类题目需要你从一组…

Java面试篇基础部分- 锁详解

可重入锁 可重入锁也叫作递归锁,是指在同一个线程中,在外层函数获取到该锁之后,内存的递归函数还可以获取到该锁。在Java语言环境下,ReentrantLock和Synchroinzed都是可重入锁的代表。 公平锁与非公平锁 公平锁(Fair Lock)是指在分配锁之前检查是否有线程在排队等待获取…

CICD从无到会

一 CICD是什么 CI/CD 是指持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;或持续交付&#xff08;Continuous Delivery&#xff09; 1.1 持续集成&#xff08;Continuous Integration&#xff09; 持续集成是…

【每天学个新注解】Day 4 Lombok注解简解(三)—@NonNull

我们在之前的三天学了Lombok常用的注解&#xff1a; 【每天学个新注解】Day 1 Lombok注解简解&#xff08;〇&#xff09;—Getter、Setter、ToString、EqualsAndHashCode、Constructor 【每天学个新注解】Day 2 Lombok注解简解&#xff08;一&#xff09;—Data、Build、Value…

【威领,德新,中达安】9.23复盘

威领这次的底部是4个月 所以这种跳空高开&#xff0c;远离5日均线的&#xff0c;如果不是近期的利好板块&#xff0c;那么第二天可能要回调5日均线。所以按照我的收益准则&#xff0c;吃一个板可以出一半了。 到顶部十字剩下一半也出掉了。 如果做长期&#xff0c;我依旧认为威…

git学习报告

文章目录 git学习报告如何配置vscode终端安装PowerShell安装 Microsoft.Powershell.Preview使用 git的使用关于团队合作 git指令本地命令&#xff1a;云端指令 git学习报告 如何配置vscode 安装powershell调教window终端&#xff0c;使其像Linux一样&#xff0c;通过Linux命令…

C语言初识(一)

目录 前言 一、什么是C语言&#xff1f; 二、第一个C语言程序 &#xff08;1&#xff09;创建新项目 &#xff08;2&#xff09;编写代码 &#xff08;3&#xff09;main函数 三、数据类型 四、变量、常量 &#xff08;1&#xff09;变量的命名 &#xff08;2&#x…

mysql复合查询 -- 合并查询(union,union all)

目录 合并查询 介绍 表数据 union 使用场景 ​编辑 示例 union all 合并查询 介绍 它不像笛卡尔积那种,将行信息做乘法 合并只是单纯地合在一起求的是两个结果集的并集,并且会自动去掉并集中的重复行 注意,因为是求并集,会将两个结果进行拼接 所以要保证列信息相同 表…

13.第二阶段x86游戏实战2-动态模块地址

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

基于Python+SQLServer实现(界面)书店销售管理管理子系统

书店销售管理管理子系统 一、设 计 总 说 明 现在社会随着计算机技术迅速发展与技术的逐渐成熟&#xff0c;信息技术已经使人们的生活发生深刻的变化。生活中的各种服务系统也使人们在生活中的联系日常销售活动方式发生了很大的变化&#xff0c;让效率较低的手工操作成为过去…

大数据新视界 --大数据大厂之 Reactjs 在大数据应用开发中的优势与实践

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…