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

JWT认证服务与授权 .netCore

1.实现流程图

2.认证信息概述

Header:System.IdentityModel.Tokens.Jwt.JwtHeader

Payload: System.IdentityModel.Tokens.Jwt.JwtPayload

Issuer: http://localhost:7200

Audience: http://localhost:7200

Expiration: 2025/4/11 15:06:14

Claim - Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid, Value: 19

Claim-Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone, Value: string

Claim -Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone, Value: string Claim-Type:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress, Value: string Claim - Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress, Value: string

Claim -Type: userName, Value: string

 Claim-Type: imageUrl, Value: string

Claim-Type: QQ, Value: string

Claim-Type: WeChat, Value: string

Claim - Type: Sex, Value: 1

Claim - Type: exp, Value: 1744383974

Claim - Type: iss, Value: http://localhost:7200

Claim - Type: aud, Value: http://localhost:7200

解释

Header(头部):

Header: System.IdentityModel.Tokens.Jwt.JwtHeader 表明了 JWT 的头部信息,它一般包含两部分内容:令牌的类型(通常是 JWT)和使用的签名算法,如 HmacSHA256 或 RSA 等。在这个输出中,只是显示了头部所属的类,并没有具体的头部信息内容。不过在实际的 JWT 中,头部会以 JSON 格式存在并经过 Base64Url 编码成为 JWT 的第一部分。

Payload(负载):Payload: System.IdentityModel.Tokens.Jwt.JwtPayload 指出了 JWT 的负载部分。负载包含声明(claims),这些声明是关于实体(通常是用户)和其他数据的陈述。同样,这里显示的是负载所属的类,实际的负载信息也会以 JSON 格式存在并经过 Base64Url 编码成为 JWT 的第二部分。

Issuer(签发者):Issuer: http://localhost:7200 表示该 JWT 的签发者,即生成和颁发这个令牌的实体,这里是本地的一个地址 http://localhost:7200。

Audience(受众):Audience: http://localhost:7200 指明了该 JWT 的预期接收者,也就是这个令牌是为谁准备的。这里的受众也是 http://localhost:7200,意味着该令牌是给本地这个地址的服务使用的。

Expiration(过期时间):Expiration: 2025/4/11 15:06:14 显示了 JWT 的过期时间,在这个时间之后,该令牌将不再被认为是有效的。

Claims(声明):http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid, Value: 19:表示用户的安全标识符(Sid),值为 19,用于唯一标识用户。

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone, Value: string:声明了用户的手机号码,但值显示为 string,可能是实际值未正确获取或填充。

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone, Value: string:其他电话号码的声明,值同样为 string。

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress, Value: string:用户街道地址的声明,值为 string。

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress, Value: string:用户电子邮件地址的声明,值为 string。

userName, Value: string:用户名的声明,值为 string。

imageUrl, Value: string:用户头像地址的声明,值为 string。

QQ, Value: string:用户 QQ 号码的声明,值为 string。

WeChat, Value: string:用户微信号码的声明,值为 string。

Sex, Value: 1:用户性别的声明,值为 1,可能表示某种性别标识(如 1 代表男性等,具体含义需参考应用的定义)。

exp, Value: 1744383974:这是一个标准的 JWT 声明,表示过期时间的 Unix 时间戳(从 1970 年 1 月 1 日 00:00:00 UTC 到过期时间的秒数),与前面显示的 2025/4/11 15:06:14 是对应的。

iss, Value: http://localhost:7200:再次声明了签发者,与前面的 Issuer 一致。

aud, Value: http://localhost:7200:再次声明了受众,与前面的 Audience 一致。

3.基础概念

3.1 JwtSecurityToken

JwtSecurityToken是在.NET 中用于处理 JSON Web Token(JWT)的一个类,它属于System.IdentityModel.Tokens.Jwt命名空间。以下是对其作用的详细介绍:

表示 JWT 结构:JWT 是一种紧凑、自包含的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。JwtSecurityToken类将 JWT 的各个部分,如头部(Header)、载荷(Payload)和签名(Signature),表示为对象的属性,使得开发人员可以方便地访问和操作 JWT 的各个元素。例如,可以通过该类的属性获取 JWT 中的签发者(Issuer)、受众(Audience)、过期时间(Expiration Time)等信息。

创建 JWT:可以使用JwtSecurityToken类来创建新的 JWT。开发人员可以设置 JWT 的各种参数,如声明(Claims)、有效期、签名密钥等,然后通过相关的 JWT 生成机制将其转换为字符串形式的 JWT,以便在网络中传输或存储。

验证 JWT:在接收方,JwtSecurityToken类可用于验证接收到的 JWT 的有效性。它可以验证 JWT 的签名是否正确,以确保令牌在传输过程中未被篡改;还可以验证令牌的有效期、签发者和受众等信息是否符合预期,从而确保令牌的合法性和安全性。

提取信息:从 JWT 中提取出包含在载荷中的各种声明信息,这些声明可以包含用户的身份信息、权限信息等。开发人员可以通过JwtSecurityToken类提供的方法和属性,方便地获取这些声明,以便在应用程序中进行授权、身份验证等操作。例如,从 JWT 中提取用户的角色信息,以确定用户是否有权访问特定的资源或执行特定的操作。

3.2 ‌MemoryCache

‌‌MemoryCache是一种基于内存的缓存服务,主要用于存储和快速访问对象,减少对外部数据源(如数据库)的频繁访问,从而提高应用程序的性能。MemoryCache是ASP.NET Core框架的一部分,位于Microsoft.Extensions.Caching.Memory命名空间中,实现了IMemoryCache接口‌1。

工作原理和过期策略

MemoryCache使用键值对来存储数据,每个数据项都可以设置一个过期时间。当缓存项目到达其过期时间或系统在资源压力下时,该项目会从缓存中删除。MemoryCache使用两种基本算法:LRU(Least Recently Used)和Expiration策略。

LRU‌:这是一种基于使用频率的算法。当内存不足以容纳新的缓存项时,此算法会移除最近最少使用的缓存项。这种策略假定未来数据访问模式将类似于过去的数据访问模式,优先保留最近频繁访问的数据。

‌Expiration‌:每个缓存项被添加到缓存时都可以设置一个过期时间。当缓存项达到其设定的过期时间后,它将从缓存中自动被移除。这种策略确保了缓存中的数据不会过时,并允许开发者根据每个缓存项的实际需求设定不同的过期时间。

适用场景和性能优化建议

MemoryCache适用于存储经常访问但更新不频繁的数据,如用户会话信息、常用配置等。通过合理设置缓存的过期时间和使用LRU算法,可以优化缓存的利用率和性能。此外,定期清理不常用的缓存项和监控内存使用情况也是保持系统性能的重要措施‌

使用方法

‌添加内存缓存服务‌:在Startup.cs文件中,通过依赖注入将内存缓存服务添加到应用程序中。例如:

csharpCopy Code

services.AddMemoryCache();

2.注入和使用内存缓存‌:在控制器或服务中注入IMemoryCache接口,并使用它来存储和检索缓存数据。例如:

csharpCopy Code

publicclassMyController : Controller

{

    privatereadonly IMemoryCache _memoryCache;

    publicMyController(IMemoryCache memoryCache)

    {

        _memoryCache = memoryCache;

    }

    public IActionResult Index()

    {

        string cachedData = null;

        if (!_memoryCache.TryGetValue("myKey", out cachedData))

        {

            cachedData = "This is the data to cache";

            _memoryCache.Set("myKey", cachedData, new MemoryCacheEntryOptions() { SlidingExpiration = TimeSpan.FromMinutes(5) });

        }

        return View(cachedData);

    }

}

3.3 特性

在.NET 中,特性(Attributes)是一种用于在运行时提供有关代码元素(如类、方法、属性等)的附加信息的机制。下面为你介绍其原理和常见应用场景:

特性原理

元数据:.NET 中的特性本质上是一种元数据,它们被嵌入到程序集的二进制代码中。这些元数据可以在运行时通过反射机制来访问,使得程序能够根据这些附加信息来做出不同的行为。

特性类:特性是通过定义特性类来实现的,这些特性类继承自 System.Attribute 基类。当在代码中使用特性时,实际上是在创建特性类的实例,并将其应用到相应的代码元素上。

特性的常见应用场景

验证:可以使用特性来标记方法或属性,以指示它们需要进行特定类型的验证。例如,在 ASP.NET Core 应用程序中,可以使用 [Required] 特性标记模型类的属性,表示该属性在接收用户输入时是必填的。

授权:在身份验证和授权场景中,特性用于限制对特定资源或操作的访问。例如,在 ASP.NET Core 中,[Authorize] 特性可以应用于控制器或控制器方法,以要求用户进行身份验证和授权才能访问相应的端点。

数据映射:在数据访问层,特性可用于将类的属性与数据库表的列进行映射。例如,Entity Framework Core 中使用 [Column] 特性来指定实体类属性与数据库表列之间的对应关系。

日志记录:通过自定义特性,可以标记需要进行日志记录的方法或类。在运行时,利用反射检查这些特性,并在方法执行前后记录相关的日志信息,以便于跟踪和调试。

Web 服务契约:在创建 Web 服务时,特性用于定义服务契约,如 [WebMethod] 特性用于标记 Web 服务中的方法,使其可以通过网络被远程调用。

3.4 有效载荷

在 JSON Web Token(JWT)中,有效载荷(Payload)里的声明(Claim)是非常重要的组成部分,以下为你详细介绍:

定义与本质:
声明是关于实体(通常指用户)和其他数据的陈述,是一组键值对。JWT 的有效载荷由一系列这样的声明组成,这些声明被编码成 JSON 对象,是 JWT 的第二部分(第一部分是头部,第三部分是签名),并且经过 Base64Url 编码。

常见的声明类型:

注册声明:这是一组预定义的声明,虽然不是强制的,但被广泛使用。常见的注册声明包括:

iss(签发者):标识令牌的签发者,例如某个服务器或应用程序。如 iss: "example.com",表示该 JWT 是由 example.com 签发的。

exp(过期时间):令牌的过期时间,是一个 Unix 时间戳。当令牌的当前时间超过这个值时,令牌就被认为是无效的。例如 exp: 1672531200,表示到对应的时间点该令牌过期。

sub(主题):令牌所面向的主体,通常是用户的唯一标识。如 sub: "123456",表示该 JWT 是关于用户 123456 的。

aud(受众):令牌的预期接收者,可以是一个或多个实体。例如 aud: ["client1", "client2"],表示该 JWT 可被 client1 和 client2 使用。

公共声明:这些声明由使用 JWT 的各方协商定义,并且不是注册声明的一部分。比如自定义的用户角色声明,如 role: "admin",表示用户具有管理员角色。

私有声明:这些声明是在使用 JWT 的各方之间保持私密的声明,通常用于在不影响其他方的情况下传递特定信息。例如应用程序内部使用的一些标识或配置信息。

作用与用途:

身份验证:通过有效载荷中的声明,服务器可以验证请求的用户身份。例如根据 sub 声明确定用户是谁,结合其他声明如 role 等进一步确认用户的身份信息。

授权:服务器可以根据声明来判断用户是否有权限访问特定的资源或执行特定的操作。例如,当用户请求访问某个 API 端点时,服务器检查 role 声明,如果用户具有相应的角色权限,则允许访问。

传递信息:可以在不同的系统或服务之间传递一些基本的用户信息或上下文信息,而无需多次查询数据库或其他数据源。比如传递用户的邮箱地址(email 声明)、手机号码(phone 声明)等信息。

3.5 API请求流程

1.创建 axios 实例:使用 axios.create 创建一个 service 实例,并设置基础 URL 和请求超时时间。

2.请求拦截器:在请求发送之前,检查本地存储中是否存在 accessToken,如果存在则将其添加到请求头的 Authorization 字段中。

3.响应拦截器:对于成功的响应,直接返回响应数据。

4.对于失败的响应,如果是 401 未授权错误且原始请求未重试过:

尝试从本地存储获取 refreshToken。

5.如果存在 refreshToken,发送刷新令牌的请求获取新的 accessToken,更新本地存储和 axios 实例的请求头,并重新发送原始请求。

6.如果刷新令牌失败或没有 refreshToken,清除本地存储的 accessToken 和 refreshToken,并跳转到登录页面,同时显示错误提示信息。

7.导出实例:将配置好的 axios 实例导出,以便在其他模块中使用来发送 API 请求。

8.原理:

分离配置和请求逻辑

创建 axios 实例并设置 baseURL 和 timeout 等配置,将通用的配置与具体的请求逻辑分离,使得代码更易于维护和修改。如果需要更改基础 URL 或调整超时时间,只需在一处进行修改,而不必在每个请求处都进行更改。

统一处理请求头

请求拦截器中统一处理 accessToken 的设置。当需要发送带有身份验证信息的请求时,只需在拦截器中统一添加 Authorization 头,而不必在每个请求方法中重复编写添加 accessToken 的代码。这样可以确保所有请求都能正确携带身份验证信息,同时也方便对 accessToken 的管理和更新。

处理身份验证和授权问题

响应拦截器中对 401 未授权错误的处理,实现了自动刷新 accessToken 的功能。当 accessToken 过期时,通过 refreshToken 来获取新的 accessToken,然后自动重试原始请求,使得用户在访问受保护资源时,即使 accessToken 过期也能继续操作,而无需用户手动重新登录,提高了用户体验。

对于 403 禁止访问错误的处理,通过提示用户没有权限操作,明确告知用户问题所在,方便用户与管理员沟通解决权限问题。

错误处理和用户引导

在响应拦截器中,对于各种错误情况进行了统一的处理。除了处理身份验证和授权相关的错误外,还可以在拦截器中对其他常见的错误进行处理,如网络错误、服务器错误等,并根据不同的错误类型给出相应的提示信息,引导用户进行正确的操作,例如提示用户检查网络连接、重新登录等,使得应用的错误处理更加统一和友好。

通过这样的流程设置,可以提高代码的复用性、可维护性和可扩展性,同时为用户提供更好的体验,确保应用在处理 API 请求时的稳定性和可靠性。

4.代码说明

4.1  accesstoken的生成

  1. 获取用户信息(用户实体类UserModel)
  2. 通过UserToClaim方法,传入UserModel,获取有效载荷

3.设置有效时间

4.实例化JwtSecurityToken对象,并对 issuer、audience、claims、expires、signingCredentials元素进行赋值。

5.读取设置的SecurityKey信息,并通过Encoding.UTF8.GetBytes转为UTF8的数组。

6.再反射转换为SymmetricSecurityKey对象key

7.再通过SigningCredentials进行HmacSha256的加密处理,形成SigningCredentials的签名对象。

8.通过JwtSecurityTokenHandler的WriteToken,将实例化的JwtSecurityToken对象,转换为字符串令牌。

​​​​​​​4.2 refreshToken的生成

1.获取新的guid。

2.基于guid,通过Claim方法来获取有效载荷。

3.设置有效时间

4.实例化JwtSecurityToken对象,并对 issuer、audience、claims、expires、signingCredentials元素进行赋值。

5.读取设置的SecurityKey信息,并通过Encoding.UTF8.GetBytes转为UTF8的数组。

6.再反射转换为SymmetricSecurityKey对象key

7.再通过SigningCredentials进行HmacSha256的加密处理,形成SigningCredentials的签名对象。

8.通过JwtSecurityTokenHandler的WriteToken,将实例化的JwtSecurityToken对象,转换为字符串令牌。

9.存入MemoryAcache,将refreshToken存储,并设置存储时长。(注意:accessToken是在调用认证的时候,再接口认证的时候进行判断的,通过时间点)《超时有两种判断,一个是在Memoryacache,一个是在认证的时候的时间点之间的时长间隔》

​​​​​​​4.3 刷新AccessToken

当accesstoken过期的情况下,则需要采用refeshtokenguid来获取最新的accesstoken,保持访问的状态。

以上的请求主要存在于 JavaScript 的基于 Axios 的 HTTP 服务封装,主要用于处理 API 请求、请求拦截、响应拦截以及使用刷新令牌(refreshToken)刷新访问令牌(accessToken)。

​​​​​​​4.4 身份验证和授权的注册

主要时进行实例化、参数设置和事件的绑定

​​​​​​​4.5  依赖注入

   builder.RegisterRefreshTokenAuthorization();

   var app = builder.Build();

​​​​​​​4.6 接口应用

接口应用实例,采用【特性的应用】

菜单获取

  /// <summary>

  /// 获取菜单列表

  /// </summary>

  /// <returns></returns>

  [HttpGet()]

  [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "MenuPolicy")]

  public async Task<JsonResult> GetMenuTreeListAsync()

  {

      //在这里要解析到当前请求的用户是

      //鉴权授权

      //这里能够拿到Userid ,说明token必然已经验证通过了

      string? strUserId = HttpContext.User?.FindFirst(ClaimTypes.Sid)?.Value;

      if (string.IsNullOrWhiteSpace(strUserId))

      {

          return await Task.FromResult(new JsonResult(new ApiDataResult<int>()

          {

              Message = "没有token权限",

              Success = false,

              OValue = 401

          }));

      }

      //strUserId = "2";

      var menusTreeList = _IMenuService.GetMenusTreeList(Convert.ToInt32(strUserId));

      var result = new JsonResult(new ApiDataResult<List<MenuTreeDto>>()

      {

          Data = menusTreeList,

          Success = true,

          Message = "获取菜单列表"

      });

      return await Task.FromResult(result);

  }

​​​​​​​4.7 前端请求的JS

  • 使用 service.interceptors.response.use 方法添加一个响应拦截器。
  • 从响应数据 response.data 中解构出 data、success、oValue 和 message 等字段。
  • 如果 success 为 false 且 oValue 为 401(表示未授权),则从 mainStore 中获取 refreshToken,调用 axionRefreshToken 函数刷新 accessToken。
  • 如果刷新成功(reponse.success 为 true),更新 mainStore 中的 accessToken,并将新的 accessToken 设置到 service 的默认请求头中,然后重新发送原始请求(service(response.config))。
  • 如果刷新失败,将用户重定向到根路由(router.push("/")),并清除 mainStore 中的 accessToken、menulist、refreshToken 和 user 等信息。
  • 如果 success 为 false 且 oValue 为 403(表示权限不足),使用 ElMessage(可能是 Element UI 中的消息提示组件)显示一个警告消息,提示用户没有操作权限。
  • 最后返回响应数据 response,让后续的代码可以处理正常的响应。

import axios from "axios";

import { apiUrl,authURL } from '../commom/index'

import mainStore from '../stores/counter'

import router from  '../router/index'

const service = axios.create({ baseURL: apiUrl() });

//请求拦截器---在axios 发起请求之前要做的事儿   aop思想~~

service.interceptors.request.use(config => {

    //可以在这里配置token

    var token = mainStore().accessToken;

    //这里就是配置 axiox 请求api的时候,带上的token

    config.headers.Authorization = 'Bearer ' + token;

    return config;

});

//响应拦截器--从服务器响应之后--得到的结果,优先处理

service.interceptors.response.use(async response => {

    //1.判断是否有权限问题

    let { data, success, oValue, message } = response.data;

    if (success == false && oValue == 401) {

        //获取refreshtoken

        var refreshToken = mainStore().refreshToken;

        const reponse = (await axionRefreshToken(refreshToken)).data;

        if (reponse.success) {

            mainStore().$patch({

                accessToken: reponse.data

            })

            service.defaults.headers.common['Authorization'] = `Bearer ${data}`;

            return service(response.config);

        }

        else {

            router.push("/");

            mainStore().$patch({

                accessToken: null,

                menulist: [],

                refreshToken: null,

                user: null

            })

        }

    } else if (success == false && oValue == 403) {

        ElMessage({

            message: "对不起,您不具备操作此功能的权限,请联系管理员",

            type: 'warning',

        })

    }

    return response;

});

//使用refreshtoken 去刷新 accesstoken

const axionRefreshToken = async (refreshtoken) => {

    const axionInstance = axios.create({

        baseURL: authURL(),

    })

    axionInstance.defaults.headers.common['Authorization'] = `Bearer ${refreshtoken}`;

    return axionInstance.get("Account");

}export default service;

​​​​​​​4.8 前端登录的代码

登录后,会将token都存储mainStore,在请求前拦截和响应的时候,可以调出来使用。

<template>

   <div class="login">

      <div class="login-content">

         <!-- 表单 -->

         <div class="login-form login-item">

            <p class="login-title">朝夕敏捷通用后台</p>

            <el-form :model="temp" :rules="rules" ref="ruleForm" label-width="70px" class="demo-ruleForm">

               <!-- 用户名 -->

               <el-form-item label="用户名" prop="name">

                  <el-input v-model="temp.name"></el-input>

               </el-form-item>

               <el-form-item label="密码" prop="password">

                  <el-input type="password" v-model="temp.password"></el-input>

               </el-form-item>

               <el-form-item>

                  <el-button @click="submitForm(ruleForm)">

                     登录</el-button>

               </el-form-item>

            </el-form>

         </div>

      </div>

   </div>

</template>

<script setup>

import { ref, reactive } from 'vue'

import { useRouter } from 'vue-router' //导入路由  

import { authURL } from '../../commom/index'

import axios from "axios";

import { ElMessage } from 'element-plus'

import mainStore from '../../stores/counter'

import jwt_decode from "jwt-decode";

const myaxios = axios.create({

   baseURL: authURL(),

})

const router = useRouter();

const temp = reactive({

   name: 'zhaoxi-admin',

   password: '123456'

})

const rules = reactive({

   name: [

      {

         required: true,

         message: '请输入用户名',

         trigger: 'blur',

      },

      {

         min: 3,

         max: 18,

         message: '长度为3-18位',

         trigger: 'blur',

      },

   ],

   password: [

      {

         required: true,

         message: '请输入密码',

         trigger: 'blur',

      },

      // {

      //    min: 3,

      //    max: 18,

      //    message: '长度为3-18位',

      //    trigger: 'blur',

      // },

   ],

})

const ruleForm = ref(null);

function submitForm(formEl) {

   formEl.validate(async valid => {

      if (valid) {

         console.log('ok');

         // 登录成功 开始加载当前用户所拥有的菜单

         let url = `Account`;

         let reponse = await myaxios.post(url, temp);

         let { data, success, message } = reponse.data;

         let user = jwt_decode(data.accesstoken)

         if (success) {

            mainStore().$patch({

               accessToken: data.accesstoken,

               refreshToken: data.refreshToken,

               user: user

            })

            router.push("/index")

         }

         else {

            ElMessage({

               message: message,

               type: 'warning',

            })

         }

      } else {

         console.log('error submit!!')

         return false

      }

   })

}

</script>

相关文章:

JWT认证服务与授权 .netCore

1.实现流程图 2.认证信息概述 Header:System.IdentityModel.Tokens.Jwt.JwtHeader Payload: System.IdentityModel.Tokens.Jwt.JwtPayload Issuer: http://localhost:7200 Audience: http://localhost:7200 Expiration: 2025/4/11 15:06:14 Claim - Type: http://schemas…...

编译原理 实验二 词法分析程序自动生成工具实验

文章目录 实验环境的准备实验实验预备知识分析案例所要做的任务实战 实验环境的准备 安装flex 安装MinGW MinGW Installation Manager页面 apply changes 下载比较耗时 只看到了一个文件&#xff0c;复制过去 配置环境变量 使用gcc -v检验是否安装完成 实验 实验预备知识…...

【C++初学】课后作业汇总复习(一)概述、输入输出、类的入门——理解封装

一、概述、输入输出、类的入门——理解封装 - 1. ab input two number output sum of a and b; #include <iostream>using namespace std;int main() {int a 0;int b 0;cin >> a >> b;cout << ab <<endl;return 0; }2.输入1~7任意一个整数&…...

数学建模:针对汽车行驶工况构建思路的延伸应用

前言&#xff1a; 汽车行驶工况构建的思简单理解为将采集的大量数据进行“去除干扰、数据处理&#xff0c;缩减至1800S的数据”&#xff0c;并可达到等效替换的目的&#xff0c;可以使在试验室快速复现&#xff1b;相应的解决思路、办法可应用在 “通过能量流采集设备大量采集…...

Qt 之opengl shader language

着色器示例代码 实际运行效果...

dolphinscheduler创建文件夹显示存储未启用的问题--已解决

只要修改api-server/comf/common.properties和standalone-server/conf/common.properties里面的内容就可以了&#xff0c;应为你要靠standalone-server这个服务启动dolphinscheduler-web&#xff0c;其他就算怎么改你重启dolphinscheduler的时候系统也不会识别新的common.prope…...

解密 Linux 线程:多线程编程与资源管理

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;线程 是一种轻量级的执行单元&#xff0c;它是进程的一部分。多个线程可以在同一个进程内并行执行任务&#xff0c;通常它们共享该进程的资源&#xff0c;如内存空间、文件描述符等。…...

Node.js net模块详解

Node.js 的 net 模块提供了基于 TCP 或 IPC 的网络通信能力&#xff0c;用于创建服务器和客户端。以下是 net 模块的核心 API 详解&#xff0c;包含类、方法、事件及示例。 1. 模块引入 const net require(net);2. 核心类与方法 2.1 net.Server 类 用于创建 TCP 或 IPC 服务…...

Node.js中fs模块详解

Node.js 中 fs 模块&#xff08;非 Promise&#xff09;API 详解 Node.js 的 fs 模块提供了同步和异步的文件系统操作。以下是非 Promise 版本的 API 详解&#xff1a; 1. 文件读取操作 const fs require(fs);// 异步读取文件 fs.readFile(file.txt, utf8, (err, data) >…...

Mouse without Borders – 用一套鼠标 / 键盘控制四台电脑

同时操控 2 台电脑&#xff0c;只需一个鼠标和键盘&#xff01;完全免费&#xff0c;由微软官方提供 | 零度解说_哔哩哔哩_bilibili Mouse Without Borders 简介‌ Mouse Without Borders&#xff08;无界鼠标&#xff09;是由微软开发的免费键鼠共享工具&#xff0c;支持在局…...

《车辆人机工程-汽车驾驶操纵实验》

汽车操纵装置有哪几种&#xff0c;各有什么特点 汽车操纵装置是驾驶员直接控制车辆行驶状态的关键部件&#xff0c;主要包括以下几种&#xff0c;其特点如下&#xff1a; 一、方向盘&#xff08;转向操纵装置&#xff09; 作用&#xff1a;控制车辆行驶方向&#xff0c;通过转…...

使用DaemonSet部署集群守护进程集

使用DaemonSet部署集群守护进程集 文章目录 使用DaemonSet部署集群守护进程集[toc]一、使用DaemonSet部署日志收集守护进程集二、管理DaemonSet部署的集群守护进程集1.对DaemonSet执行滚动更新操作2.对DaemonSet执行回滚操作3.删除DaemonSet 一、使用DaemonSet部署日志收集守护…...

破解升腾c10,改造成下载机(第二篇:获取xterm终端)

当c10刷好华为ct3100系统后&#xff0c;就开始获取xterm终端&#xff0c;然后再安装entware. 第一步&#xff1a;获取xterm终端。 点击桌面左下角的工具图标 再点browser 输入百度网址&#xff0c;访问&#xff01; 然后再将网页另存为&#xff5e;&#xff5e;&#xff5e;…...

浏览器多开

使用浏览器的用户功能&#xff0c;创建多个用户即可完成浏览器多开的需求&#xff0c;插件等相对独立 需要命名 然后就可以通过多个用户切换来实现多开了&#xff0c;不同任务选择不同用户...

使用Python实现的音符生成和节拍器程序

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 **摘要****先决条件****设置**生成音符频率播放音符节拍器合并结论摘要 节拍器和随机音符生成器各有用途,但单独使用时功能有限。本…...

【生活相关-日语-日本-东京-留学生-搬家后或新入驻-水道局申请饮用水(1)-办理手续】

【生活相关-日语-日本-东京-搬家后-水道局申请饮用水-办理手续】 1、前言2、情况说明&#xff08;1&#xff09;他人代办&#xff08;2&#xff09;打电话&#xff08;3&#xff09;网络申请&#xff08;4&#xff09;你将会面临什么&#xff0c;主要步骤&#xff08;5&#xf…...

PyTorch模型构造实战:从基础到复杂组合

本文通过多个示例演示如何使用PyTorch构建不同类型的神经网络模型&#xff0c;涵盖基础多层感知机、自定义块、顺序块以及复杂组合模型。所有代码均附带输出结果&#xff0c;帮助读者直观理解模型结构。 1. 多层感知机&#xff08;MLP&#xff09; 使用nn.Sequential快速构建一…...

【高性能缓存Redis_中间件】一、快速上手redis缓存中间件

一、铺垫 在当今的软件开发领域&#xff0c;消息队列扮演着至关重要的角色。它能够帮助我们实现系统的异步处理、流量削峰以及系统解耦等功能&#xff0c;从而提升系统的性能和可维护性。Redis 作为一款高性能的键值对数据库&#xff0c;不仅提供了丰富的数据结构&#xff0c;…...

并发编程--互斥锁与读写锁

并发编程–互斥锁与读写锁 文章目录 并发编程--互斥锁与读写锁1. 基本概念2. 互斥锁2.1 基本逻辑2.2 函数接口2.3示例代码12.4示例代码2 3. 读写锁3.1 基本逻辑3.2示例代码 1. 基本概念 互斥与同步是最基本的逻辑概念&#xff1a; 互斥指的是控制两个进度使之互相排斥&#x…...

Linux下Docker安装超详细教程(以CentOS为例)

前言 Docker 已成为现代应用开发和部署的标配工具。本教程将手把手教你 在 CentOS 系统上安装 Docker&#xff0c;涵盖从环境准备到验证安装的全流程&#xff0c;并解决常见问题。无论你是运维工程师还是开发者&#xff0c;均可快速上手。 一、环境要求 操作系统 CentOS 7 或更…...

Ubuntu 服务器版本 设置socket服务(Python)

1. 确定 Socket 类型 Socket 服务可以是: 网络 Socket:基于 TCP/UDP 协议(如 Web 服务器、API 服务)。 Unix Domain Socket:本地进程间通信(如 Docker、MySQL 默认使用)。 2. 编写一个简单的 Socket 服务示例(Python) 以 Python 为例,创建一个 TCP Socket 服务:…...

对于GAI虚假信息对舆论观察分析

摘要 生成式人工智能&#xff08;Generative Artificial Intelligence, GAI&#xff09;的技术革新重构了信息生产机制&#xff0c;但也加剧了虚假信息对舆论生态的异化风险。 关键词&#xff1a;生成式人工智能、虚假信息、舆论异化、智能治理 一、生成式人工智能虚假信息下…...

HTTP:三.HTTP连接

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本数据的应用层协议。它是互联网上最常用的协议,用于在客户端和服务器之间传输数据。HTTP协议通常用于从Web服务器传输网页和文件到客户端浏览器,并支持其他用途,如传输API数据和传输文件。 HTTP连接是指客户端向服务…...

hyper-v server服务器部署远程访问(我目前环境:hyper-v服务器+路由器+公网ip)

Hyper-v server部署(裸金属方式) 系统镜像下载安装# 下载地址:17763.737.190906-2324.rs5_release_svc_refresh_SERVERHYPERCORE_OEM_x64FRE_zh-cn_1.iso 安装的过程很简单,和安装Windows操作系统没啥区别,这里就不记录了。 安装过程可参考:安装Hyper-v Server 2016 部…...

MCP遇见Web3:从边缘计算到去中心化的无限想象

MCP遇见Web3:从边缘计算到去中心化的无限想象 在数字化转型的浪潮中,边缘计算(MCP,Micro Control Protocol)和Web3技术分别在计算效率与去中心化架构上发挥着各自的优势。当两者融合,会碰撞出哪些火花?作为一名技术极客,我最近开始深度研究MCP与Web3工具的集成,试图探…...

【HarmonyOS Next之旅】DevEco Studio使用指南(十三) -> ArkTS/TS代码重构

目录 1 -> Refactor-Extract代码提取 2 -> Refactor-Convert代码转换 3 -> Refactor-Rename代码重命名 4 -> Move File 5 -> Safe Delete 1 -> Refactor-Extract代码提取 在编辑器中支持将函数内、类方法内等区域代码块或表达式&#xff0c;提取为新方…...

STM32 HAL DHT11驱动程序

DHT11驱动程序会占用TIM3定时器&#xff0c;进行高精度延时。程序共包含4个文件 DHT11.c DHT11.h delay.c delay.h DHT11.c #include "stm32f1xx_hal.h" #include "dht11.h" #include "delay.h" // 添加延时头文件 #define DHT_PORT GPIOB…...

asm汇编源代码之文件操作相关

提供7个子程序:   1. 关闭文件 FCLOSE   2. 打开文件 FOPEN   3. 文件大小 FSIZE   4. 读文件 FREAD   5. 写文件 FWRITE   6. 建立文件 FCREATE   7. 读取或设置文件指针 FPOS 具体功能及参数描述如下 ; ---------------------------- FCLOSE PROC  FAR ; IN…...

Github 2025-04-12 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-04-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10TypeScript项目2uv: 极快的Python软件包安装程序和解析器 创建周期:147 天开发语言:Rust协议类型:Apache License 2.0Star数量:7…...

JAVA学习-练习试用Java实现“实现一个Java程序,对大数据集中的数据进行类型转换”

问题&#xff1a; 实现一个Java程序&#xff0c;对大数据集中的数据进行类型转换。 解答思路&#xff1a; 在Java中&#xff0c;对大数据集中的数据进行类型转换通常意味着将一种数据类型转换为另一种数据类型。以下是一个简单的Java程序示例&#xff0c;它演示了如何对大数据集…...

Android基础彻底解析-APK入口点,xml,组件,脱壳,逆向

第一章:引言与背景 Android逆向工程,作为一种深入分析Android应用程序的技术,主要目的就是通过分析应用的代码、资源和行为来理解其功能、结构和潜在的安全问题。它不仅仅是对应用进行破解或修改,更重要的是帮助开发者、研究人员和安全人员发现并解决安全隐患。 本文主要对…...

Spark RDD算子详解:从入门到精通

一、前言 在大数据处理领域&#xff0c;Apache Spark凭借其高效的内存计算能力&#xff0c;成为了流行的分布式计算框架。RDD&#xff08;Resilient Distributed Dataset&#xff09;是Spark的核心概念之一&#xff0c;它是一个分布式的数据集合&#xff0c;提供了丰富的操作接…...

Bootstrap4 卡片

Bootstrap4 卡片 Bootstrap 是一个流行的前端框架&#xff0c;它提供了丰富的组件和工具&#xff0c;使得开发者可以快速构建响应式、美观的网页。其中&#xff0c;Bootstrap4 中的卡片组件&#xff08;Card&#xff09;是一个非常实用的功能&#xff0c;可以用来展示图片、文…...

【随行付-注册安全分析报告-无验证方式导致隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

深入解析Antogen意图识别模型:从原理到实践

一、意图识别基础概念 1.1 什么是意图识别 意图识别(Intent Recognition)是自然语言处理(NLP)中的核心任务&#xff0c;旨在确定用户输入背后想要表达的目的或行动请求。它是对话系统理解用户的第一步&#xff0c;直接影响后续的对话管理和响应生成质量。 关键特征&#xff…...

企业年报问答RAG挑战赛冠军方案:从零到SotA,一战封神

RAG挑战赛是什么&#xff1f; 任务是基于企业年报构建问答系统。比赛日的流程简而言之&#xff1a; 解析阶段&#xff1a;获得100份随机企业的年报&#xff08;PDF格式&#xff0c;每份最多1000页&#xff09;&#xff0c;限时2.5小时完成解析并构建数据库。问答阶段&#xf…...

深入理解 HTML5 语义元素:提升网页结构与可访问性

引言 在构建网页的过程中&#xff0c;合理的结构与清晰的语义对于网页的质量、可维护性以及搜索引擎优化&#xff08;SEO&#xff09;都至关重要。HTML5 引入了一系列语义元素&#xff0c;为开发者提供了更精准描述网页内容的工具。本文将深入探讨 HTML5 语义元素的作用、使用…...

DeepSeek vs Grok vs ChatGPT:三大AI工具优缺点深度解析

一、DeepSeek&#xff1a;低成本与中文专精的本地化AI 优点 中文处理能力卓越 DeepSeek针对中文语法和文化背景进行了深度优化&#xff0c;尤其在古文翻译、诗歌创作和技术文档生成中表现突出&#xff0c;远超ChatGPT的中文支持能力。高效推理与低成本 采用混合专家&#xff…...

MCP(模型上下文协议)简单案例

MCP&#xff08;模型上下文协议&#xff09;的标准化接口 MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是由Anthropic开发的一种开放协议&#xff0c;旨在标准化大型语言模型&#xff08;LLM&#xff09;与外部数据源和工具的交互方式1。它就…...

BGP基础概念与核心架构

一、BGP 协议定义与定位 BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09; 是互联网中唯一的域间路由协议&#xff08;EGP&#xff09;&#xff0c;用于在不同自治系统&#xff08;AS&#xff09;之间交换路由信息。与 OSPF、IS-IS 等域内路由协议…...

【经济保护主义叙事】

第一层&#xff1a;表面逻辑——经济保护主义叙事 公开理由&#xff1a;特朗普宣称加征关税是为了“保护美国制造业”“减少贸易逆差”“维护国家安全”&#xff0c;并强调通过关税迫使贸易伙伴降低壁垒&#xff0c;促进产业链回流美国。 底层逻辑&#xff1a;通过民族主义叙事…...

遵循IEC 62304:构建安全可靠的医疗器械软件

目录 一、IEC 62304 标准概述 1. 标准定位与适用范围 二、核心内容与要求 1. 软件安全等级&#xff08;Software Safety Classification&#xff09; &#xff08;1&#xff09;分级标准 &#xff08;2&#xff09;分级依据 &#xff08;3&#xff09;验证要求 2. 软件…...

ARM 架构下 spin_lock 实现

阅读该文章前&#xff0c;需要对原子指令有所了解&#xff0c;推荐阅读 聊一聊原子操作和弱内存序 1、概念 内核当发生访问资源冲突的时候&#xff0c;可以有两种锁的解决方案选择&#xff1a; 一个是原地等待一个是挂起当前进程&#xff0c;调度其他进程执行&#xff08;睡眠…...

计算机视觉算法实现——SAM实例分割:原理、实现与应用全景

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 1. 实例分割领域概述 实例分割(Instance Segmentation)是计算机视觉领域最具挑战性的任务之一&#xff0c…...

asm汇编字符串操作

提供8个子程序: 1. 字符串长度 STRLEN 2. 字符串替换 REPLACE 3. 字节查找 SEARCHB 4. 双字节查找 SEARCHW 5. 输入字符串 GETSTR 6. 输出字符串 OUTSTR 7. 复制字符串 COPYSTR 8. 查找字符串 SRCHSTR 具体功能及参数描述如下 STRLEN PROC  FAR ; IN: ;   DS:DXSTRING ;…...

[MSPM0开发]之三MSPM0G3507之时钟系统

一、MSPM0G3507时钟模块概述 MSPM0G3507的时钟系统隶属于其电源管理和时钟单元 (PMCU) 。 PMCU主要负责电源管理、时钟配置和复位控制功能。 时钟模块包含内部和外部 振荡器 oscillators、 时钟监测器 clock monitors以及时钟选择和控制逻辑。 提供了频率时钟计数器frequency …...

如何绕过WAF实现SQL注入攻击?​

引言​​ 在渗透测试中&#xff0c;SQL注入&#xff08;SQLi&#xff09;始终是Web安全的核心漏洞之一。然而&#xff0c;随着企业广泛部署Web应用防火墙&#xff08;WAF&#xff09;&#xff0c;传统的注入攻击往往会被拦截。本文将分享一种​​绕过WAF检测的SQL注入技巧​​…...

基础数学:图论与信息论

微积分与概率论由此进&#xff1a;基础数学&#xff1a;微积分和概率与统计-CSDN博客 线代与优化理论由此进&#xff1a;基础数学&#xff1a;线性代数与优化理论-CSDN博客 数值分析与离散数学由此进&#xff1a;基础数学&#xff1a;数值分析与离散数学-CSDN博客 四、图论与…...

05-RabbitMQ 面试题-mk

1.RabbitMQ-如何保证消息不丢失? 消息中间件的好处 提供了系统之间的异步调用,让服务与服务之间解耦削峰、填谷场景: 异步发送(验证码、短信、邮件…)MySQL和Redis , ES之间的数据同步分布式事务削峰填谷 消息发送者(publisher )把消息发送给交换机(exchange),由交…...

当当平台商品详情接口设计与调用指南

当当平台商品详情接口设计与调用指南 接口名称 GET /api/product/detail 图书商品核心信息查询接口 请求参数说明 参数名称 类型 是否必填 说明 isbn string 是 国际标准书号(支持13位/10位) product_id string 否 平台内部商品编号&#xff08;与…...