Spring Security自定义认证授权过滤器

自定义认证授权过滤器

  • 自定义认证授权过滤器
  • 1、SpringSecurity内置认证流程
  • 2、自定义Security认证过滤器
    • 2.1 自定义认证过滤器
    • 2.2 定义获取用户详情服务bean
    • 2.3 定义SecurityConfig类
    • 2.4 自定义认证流程测试
  • 3、 基于JWT实现无状态认证
    • 3.1 认证成功响应JWT实现
    • 3.2 SpringSecurity基于Jwt实现认证小结
  • 4、自定义Security授权过滤
    • 4.1 授权流程说明
    • 4.2 授权实现流程
    • 4.3 配置自定义授权过滤器
  • 5、自定义权限拒绝处理
    • 5.1 自定义认证用户权限拒绝处理器
    • 5.2 自定义匿名用户拒绝处理器
  • 6、自定义认证授权整体流程小结

自定义认证授权过滤器

如果对 Spring Security 了解不够请看这篇。 https://blog.csdn.net/m0_62943934/article/details/134815311

需求:

SpringSecurity 内置的认证只能接收 form 表单提交的账户、密码信息。并且内部是使用 HttpServletRequest 的 getParameter 方法获取账户信息的,同时如果需要对需求进行扩展,内置的授权方式就不够看了。

@Nullable
protected String obtainUsername(HttpServletRequest request) {return request.getParameter(this.usernameParameter);
}

但是,我们需要清楚现在的大部分项目都是基于前后端分离的架构来进行实现的。而这种情况下前段基本都会使用类似于axios这种发送异步请求,而这时账户信息就不能使用 getParameter 方法获取了。需要使用获取流数据的方式,此时就需要我们自己定义认证授权过滤器

1、SpringSecurity内置认证流程

通过研究SpringSecurity内置基于form表单认证的UsernamePasswordAuthenticationFilter过滤器,我们可以仿照自定义认证过滤器:

在这里插入图片描述

内置认证过滤器的核心流程:

在这里插入图片描述

核心流程梳理如下:

  • 认证过滤器(UsernamePasswordAuthentionFilter)接收 form 表单提交的账户、密码信息,并封装成UsernamePasswordAuthenticationToken认证凭对象;
  • 认证过滤器调用认证管理器AuthenticationManager进行认证处理;
  • 认证管理器通过调用用户详情服务获取用户详情UserDetails;
  • 认证管理器通过密码匹配器PasswordEncoder进行匹配,如果密码一致,则将用户相关的权限信息一并封装到Authentication认证对象中;
  • 认证过滤器将Authentication认证过滤器放到认证上下文,方便请求从上下文获取认证信息;

2、自定义Security认证过滤器

SpringSecurity 内置的认证过滤器是基于post请求且为form表单的方式获取认证数据的,那如何接收前端Json异步提交的数据据实现认证操作呢?

显然,我们可仿照UsernamePasswordAuthentionFilter类自定义一个过滤器并实现认证过滤逻辑;

2.1 自定义认证过滤器

UsernamePasswordAuthentionFilter过滤器继承了模板认证过滤器AbstractAuthenticationProcessingFilter抽象类,我们也可仿照实现:

package com.shen.security.security_test.config;import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;/*** @author shenyang* @version 1.0* @Date 2024/3/11 16:29* 认证过滤器**/
public class MyUserNamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public static final String USERNAME_KEY = "username";public static final String PASSWORD_KEY = "password";/*** 自定义构造器,传入登录认证的url地址** @param defaultFilterProcessesUrl*/public MyUserNamePasswordAuthenticationFilter(String defaultFilterProcessesUrl) {super(defaultFilterProcessesUrl);}/*** 尝试去认证的方法** @param request* @param response* @return* @throws AuthenticationException* @throws IOException* @throws ServletException*/@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {//请求必须是post请求 并且请求类型必须是jsonif (!request.getMethod().equalsIgnoreCase("POST")//忽略大小写&! MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(request.getContentType())) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}//获取post请求ajax的数据流 并且将其数据流中的数据反序列化成MapHashMap<String,String> userInfo = new ObjectMapper().readValue(request.getInputStream(), HashMap.class);String username = userInfo.get(USERNAME_KEY);username = (username != null) ? username : "";username = username.trim();String password = userInfo.get(PASSWORD_KEY);password = password != null ? password : "";//组装认证的票据对象 将用户名和密码信息封装到认证票据对象下UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);// Allow subclasses to set the "details" property//setDetails(request, authRequest);//调用认证管理器认证指定的票据对象   交给认证管理器认证票据对象return this.getAuthenticationManager().authenticate(authRequest);}public MyUserNamePasswordAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {super(requiresAuthenticationRequestMatcher);}/*** 认证成功后执行的方法* @param request* @param response* @param chain 过滤器链* @param authResult 认证对象信息* @throws IOException* @throws ServletException*/@Overrideprotected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {User principal = (User) authResult.getPrincipal();String username = principal.getUsername();Collection<GrantedAuthority> authorities = principal.getAuthorities();String password = principal.getPassword();//响应数据格式jsonresponse.setContentType(MediaType.APPLICATION_JSON_VALUE);//编码格式response.setCharacterEncoding("UTF-8");Map<String,String> infos = new HashMap<>();infos.put("msg","登录成功");infos.put("data","");infos.put("code","1");//响应response.getWriter().write(new ObjectMapper().writeValueAsString(infos));}@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {//响应数据格式jsonresponse.setContentType(MediaType.APPLICATION_JSON_VALUE);//编码格式request.setCharacterEncoding("UTF-8");Map<String,String> infos = new HashMap<>();infos.put("msg","登录失败");infos.put("data","");infos.put("code","1");//响应response.getWriter().write(new ObjectMapper().writeValueAsString(infos));}
}

2.2 定义获取用户详情服务bean

package com.shen.service;import com.shen.entity.TbUser;
import com.shen.mapper.TbUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.List;/*** @author by shen* @Date 2024/1/23* @Description*/
@Service("userDetailsService")
public class MyUserDetailServiceImpl implements UserDetailsService {@Autowiredprivate TbUserMapper tbUserMapper;/*** 使用security当用户认证时,会自动将用户的名称注入到该方法中* 然后我们可以自己写逻辑取加载用户的信息,然后组装成UserDetails认证对象* @param userName* @return 用户的基础信息,包含密码和权限集合,security底层会自动比对前端输入的明文密码* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {//1.根据用户名称获取用户的账户信息TbUser dbUser=tbUserMapper.findUserInfoByName(userName);//判断该用户是否存在if (dbUser==null) {throw new UsernameNotFoundException("用户名输入错误!");}//2.组装UserDetails对象//获取当前用户对应的权限集合(自动将以逗号间隔的权限字符串封装到权限集合中)List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList(dbUser.getRoles());/*参数1:账户参数2:密码参数3:权限集合*/User user = new User(dbUser.getUsername(), dbUser.getPassword(), list);return user;}
}

2.3 定义SecurityConfig类

配置默认认证过滤器,保证自定义的认证过滤器要在默认的认证过滤器之前;

package com.shen.security.config;import com.shen.security.filter.MyUserNamePasswordAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity//开启web安全设置生效
//开启SpringSecurity相关注解支持
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 配置授权策略* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable();//禁用跨站请求伪造http.authorizeRequests()//对资源进行认证处理.antMatchers("/authentication/form").permitAll()//登录路径无需拦截.anyRequest().authenticated();  //除了上述资源外,其它资源,只有 认证通过后,才能有权访问http//坑-过滤器要添加在默认过滤器之前,否则,登录失效.addFilterBefore(myUserNamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter() throws Exception {构造认证过滤器对象,并设置默认登录路径MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter =new MyUserNamePasswordAuthenticationFilter("/authentication/form");myUserNamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());return myUserNamePasswordAuthenticationFilter;}
}

2.4 自定义认证流程测试

在这里插入图片描述

3、 基于JWT实现无状态认证

JWT是无状态的,所以在服务器端无需存储和维护认证信息,这样会大大减轻服务器的压力,所以我们可在自定义的认证过滤器认证成功后通过successfulAuthentication方法向前端颁发token认证字符串;

3.1 认证成功响应JWT实现

测试工程导入Jwt工具类,集成流程如下:

    /*** 认证工程处理方法* @param request* @param response* @param chain* @param authResult* @throws IOException* @throws ServletException*/@Overrideprotected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication authResult) throws IOException, ServletException {//认证主体信息,此时以填充用户权限信息UserDetails principal = (UserDetails) authResult.getPrincipal();//组装响应前端的信息String username = principal.getUsername();Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();//构建JwtToken 加入权限信息是为了将来访问时,jwt解析获取当前用户对应的权限,做授权的过滤//权限字符串格式:[P5, ROLE_ADMIN]String token = JwtTokenUtil.createToken(username, authorities.toString());HashMap<String, String> info = new HashMap<>();info.put("name",username);info.put("token",token);//设置响应格式response.setContentType(MediaType.APPLICATION_JSON_VALUE);//内容编码格式response.setCharacterEncoding("utf-8");response.getWriter().write(new ObjectMapper().writeValueAsString(info));}

测试获取认证Token

3.2 SpringSecurity基于Jwt实现认证小结

在这里插入图片描述

4、自定义Security授权过滤

上一小结认证成功后向请求方响应了token信息,那么请求方访问其它系统资源时,就需要带着这个token到后台,后台需要一个授权过滤器获取token信息,并解析用户权限信息,将信息封装到UsernamePasswordAuthentionToken对象存入安全上下文,方便请求时安全过滤处理;

4.1 授权流程说明

在这里插入图片描述

4.2 授权实现流程

在正式开始之前先了解一个 Spring Security 提供的抽象类 OncePerRequestFilter。这是 Spring Security 框架中的一个特殊过滤器,用于确保在一次请求中只通过一次过滤器链,不管请求被转发到哪里。这个特性尤其重要,因为它可以防止在同一请求中多次执行相同的安全逻辑。

OncePerRequestFilter 的主要特点:

  • 单次执行:确保在一次请求的生命周期内,不管请求如何被转发或重定向,过滤器仅被执行一次。
  • 自定义安全逻辑:它经常被用来实现自定义的安全逻辑,如认证、授权、或者检查请求中的某些特定信息等。
  • 扩展点:作为 Spring Security 过滤器链的一部分,它提供了一个扩展点,允许开发者在标准的过滤器执行流程中插入自己的逻辑。

定义授权过滤器:

package com.shen.security.config;import com.google.gson.Gson;
import com.shen.security.utils.JwtTokenUtil;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;/*** @author by shen* @Date 2024/1/23* @Description 权限认证filter*/
public class AuthenticationFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {//1.获取http请求头中携带的jwt票据字符串(注意:如果用户尚未认证,则jwt票据字符串不存在)String jwtToken = request.getHeader(JwtTokenUtil.TOKEN_HEADER);//2.判断请求中的票据是否存在if (StringUtils.isBlank(jwtToken)) {//如果票据为空,可能用户准备取认证,所以不做拦截,但是此时UsernamePasswordAuthenticationToken对象未生成,那么即使放行本次请求//后续的过滤器链中也会校验认证票据对象filterChain.doFilter(request,response);return;}//3.校验票据Claims claims = JwtTokenUtil.checkJWT(jwtToken);//票据失效if (claims==null) {//票据失效则提示前端票据已经失效,需要重新认证response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setContentType("utf-8");response.getWriter().write("jwt token failure!!");return;}//4.从合法的票据中获取用户名和权限信息//用户名String username = JwtTokenUtil.getUsername(jwtToken);//权限信息 [P5, ROLE_ADMIN]String roles = JwtTokenUtil.getUserRole(jwtToken);//将数组格式的字符串转化成权限对象集合String comStr = StringUtils.strip(roles, "[]");List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(comStr);//5.组装认证成功的票据对象(认证成功时,密码位置null)UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, null, authorityList);//6.将认证成功的票据对象保存到安全上下文中,方便后续的过滤器直接获取权限信息SecurityContextHolder.getContext().setAuthentication(token);//7.发行过滤器filterChain.doFilter(request,response);}
}

4.3 配置自定义授权过滤器

/*** 给访问的资源配置权限过滤* @param http* @throws Exception*/
@Override
protected void configure(HttpSecurity http) throws Exception {http.csrf().disable();//禁用跨站请求伪造http.authorizeRequests()//对资源进行认证处理.antMatchers("/myLogin").permitAll()//登录路径无需拦截.anyRequest().authenticated();  //除了上述资源外,其它资源,只有 认证通过后,才能有权访问//添加自定义的认证过滤器:UsernamePasswordAuthenticationFilter是默认的登录认证过滤器,而我们重写了该过滤器,所以访问时,应该先走我们//自定义的过滤器http.addFilterBefore(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);//配置授权过滤器,过滤一切资源http.addFilterBefore( authenticationFilter(),MyUsernamePasswordAuthenticationFilter.class);
}/*** 自定义授权过滤器* 过滤一切被访问的资源* @return*/
@Bean
public AuthenticationFilter authenticationFilter(){AuthenticationFilter filter = new AuthenticationFilter();return filter;
}

访问测试:

​ 略

5、自定义权限拒绝处理

上一小结当用户未认证访问资源或者认证成功后访问没有权限的资源时,响应给前端的信息不友好,我们可通过自定义权限访问拒绝的处理器来友好提醒用户;

5.1 自定义认证用户权限拒绝处理器

通过实现AccessDeniedHandler接口实现:

    /*** 自定义登录认证策略配置授权策略 -1* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {//......http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException e) throws IOException, ServletException {//认证用户访问资源时权限拒绝处理策略response.getWriter().write("no permission......reject....");}});}

效果:

在这里插入图片描述

5.2 自定义匿名用户拒绝处理器

同样通过实现AuthenticationEntryPoint接口实现:

    /*** 自定义登录认证策略配置授权策略 -1* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {//......http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException e) throws IOException, ServletException {//认证用户访问资源时权限拒绝处理策略response.getWriter().write("no permission......reject....");}}).authenticationEntryPoint(new AuthenticationEntryPoint(){@Overridepublic void commence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException) throws IOException, ServletException {response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding("UTF-8");response.getWriter().write("匿名用户无权访问");});}
}

6、自定义认证授权整体流程小结

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

OceanBase中binlog service 功能的试用

OBLogProxy简介 OBLogProxy即OceanBase的增量日志代理服务&#xff0c;它可与OceanBase建立连接并读取增量日志&#xff0c;从而为下游服务提供了变更数据捕获&#xff08;CDC&#xff09;的功能。 关于OBLogProxy的详尽介绍与具体的安装指引&#xff0c;您可以参考这篇官方OB…

基于R语言的水文、水环境模型优化技术及快速率定方法与多模型教程

原文链接&#xff1a;基于R语言的水文、水环境模型优化技术及快速率定方法与多模型教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247597847&idx7&snd71869f1290d0ef9dd7fd3f74dd7ca33&chksmfa823ef0cdf5b7e655af5e773a3d3a1b200632a5981f99fe72f0…

普林斯顿算法讲义(一)

原文&#xff1a;普林斯顿大学算法课程 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 1. 基础知识 原文&#xff1a;algs4.cs.princeton.edu/10fundamentals 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 概述。 本书的目标是研究各种重要和有用的算法——…

多线程编程

多线程写作类 倒计时协调器CountDownLatch 某个线程需要等待其他线程执行到特定操作结束即可。例如&#xff1a;在多Web服务中&#xff0c;在启动指定服务时需要启动若干启动过程中比较耗时的服务&#xff0c;为了尽可能减少服务启动过程的总耗时&#xff0c;该服务会使用专门…

深入探讨MES管理系统与MOM系统之间的关系

在制造业的信息化浪潮中&#xff0c;各种系统与技术层出不穷&#xff0c;其中MES制造执行系统和MOM制造运营管理无疑是备受瞩目的两大主角。尽管它们都是制造业信息化不可或缺的部分&#xff0c;但许多人对它们之间的区别与联系仍感到困惑。本文将对MES管理系统和MOM系统进行深…

#数据结构 线性表的顺序存储

目录 每日文案 一、线性表的定义 二、线性表的操作 顺序表的存储结构 顺序表的初始化操作 判断顺序表是否为空表 将顺序表置为空表 计算顺序表中的元素个数 取出顺序表中的对应位置元素 取出对应数值的位序 在对应位置插入元素 将对应位置的元素删除 将顺序表中的数据…

1.Python数据分析—数据分析与挖掘详讲

1.Python数据分析—数据分析与挖掘详讲 一个人简介二数据分析与挖掘概述三什么是数据分析和挖掘四数据分析与挖掘在不同领域的应用4.1医疗领域&#xff1a;4.1.1 建立疾病数据库&#xff1a;4.1.2 临床决策支持&#xff1a;4.1.3 疾病预警和监控&#xff1a; 4.2 电子商务领域&…

第12章 指针

以下内容是学习尚硅谷 12.1 指针基本介绍 1&#xff09;指针是C语言的精华&#xff0c;也是C语言的难点 2&#xff09;指针&#xff0c;也就是内存的地址&#xff1b;所谓指针变量&#xff0c;也就是保存了内存地址的变量。关于指针的基本使用&#xff0c;在讲变量的时候做了…

d2-crud-plus 使用小技巧(四)—— 搜索限制只能输入数字

需求 搜索时有些字段需要限制&#xff0c;比如只能输入数字&#xff0c;不能存在其他字符包括空格。 效果 事情焦点后先触发校验&#xff0c;在触发查询。 代码 crud.js export const crudOptions (vm) > {return {columns: [{title: 号码,key: number,search: { //…

比Let‘s Encrypt更简单更齐全的免费证书申请教程

步骤一 打开JoySSL官网&#xff0c;注册属于你的专属账号&#xff1b; 永久免费SSL证书申请地址真正完全且永久免费&#xff01;不用您花一分钱&#xff0c;SSL证书免费使用90天&#xff0c;并且还支持连续签发。JoySSL携手全球权威可信顶级根&#xff0c;自研新一代SSL证书&…

【汇编】#3 8086与数据有关的寻址方式

文章目录 操作码与操作数1. 8086处理器的与数据有关的寻址方式1.1 立即数寻址方式1.2 寄存器寻址方式 2. 有效&#xff08;偏移&#xff09;地址&#xff08;effective address&#xff0c;EA&#xff09;与缺省段寄存器选择tips:段跨越前缀2.1 直接寻址tips:直接寻址与立即寻址…

GitOps实践之Argo CD (2)

argocd 【-1】argocd可以解决什么问题? helm 部署是手动的?依赖流水线。而有时候仅仅更新一个小东西,流水线跑好久,CD真的不应该和CI耦合。不同环境的helm配置不同,手动修改问题多,可以用git管理起来,例如分不同环境用目录区分。argocd创建应用可以不通环境部署到不同集…

Seata 2.x 系列【12】高可用集群部署

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Seata 版本 2.0.0 本系列Spring Boot 版本 3.2.0 本系列Spring Cloud 版本 2023.0.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 概述2. 搭建演…

声卡喊话IP喇叭,IP网络吸顶天花喇叭

声卡喊话IP喇叭&#xff0c;IP网络吸顶天花喇叭 SV-7043VP是一款ip/sip网络吸顶喇叭&#xff0c;具有10/100M以太网接口&#xff0c;从网络接口接收网络的音频数据后播放。本网络吸顶喇叭可以与其他广播主机、服务器软件和采播主机配合使用&#xff0c;实现音频的播放&#xf…

大语言模型:Query Rewriting for Retrieval-Augmented Large Language Models

总体思路 作者首先指出大语言模型虽然取得了很好的效果&#xff0c;但是仍然存在幻觉和时间顺序混乱的问题&#xff0c;因此需要额外知识库和LLM内部知识库相结合&#xff0c;来修正&#xff1b;因此优化传统的retriever-reader的方案成为需要&#xff1b;目前的研究方案当中使…

log4cplus在Qt linux中的应用与问题解决

log4cplus在Qt linux中的应用与问题解决 背景log4cplus下载遇到问题&#xff1a;libm.so.6:undefined reference to __strtof128_nanGLIBC_PRIVATE‘解决方案编译生成在Qt工程里面添加对应依赖编译运行成功 背景 最近工作中需要用到log4cplus的日志做一些记录&#xff0c;用了…

Linux——ELK日志分析系统

实验环境 虚拟机三台CentOS 7.9&#xff0c; 组件包 elasticsearch-5.5.0.rpm elasticsearch-head.tar.gz node-v8.2.1.tar.gz phantomjs-2.1.1-linux-x86_64.tar.bz2 logstash-5.5.1.rpm kibana-5.5.1-x86_64.rpm 初始…

Lombok原理及实例(Java) - 简化JavaBean开发

Lombok 1.作用:简化javabean开发 2.使用:a.下插件 -> 如果是idea2022不用下载了,自带b.导lombok的jar包c.修改设置 1.lombok介绍 Lombok通过增加一些“处理程序”&#xff0c;可以让javabean变得简洁、快速。 Lombok能以注解形式来简化java代码&#xff0c;提高开发效…

优选算法[1]

目录 1.双指针&#xff1b; 2.滑动窗口&#xff1b; 3.二分查找&#xff1b; 4.前缀和&#xff1b; 1.双指针&#xff1b; 包括对撞指针和快慢指针(一般用来循环&#xff09;&#xff1b; 题目类型&#xff1a;移动零&#xff0c;复写零&#xff0c;快乐数&#xff0c;盛…

【UE5】动画混合空间的基本用法

项目资源文末百度网盘自取 什么是动画混合空间 混合空间分为两种: 通过一个数值控制通过两个数值控制 下面通过演示让大家更直观地了解 在Character文件夹中单击右键,选择动画(Animation),选择旧有的混合空间1D 然后选择骨骼&#xff08;动画是基于骨骼显示的,所以需要选择…