SpringSecurity+前端项目+redis完成认证授权的代码

news2024/11/13 11:00:16

1. 前端准备工作--都在全局main.js页面中设置的

1.1. 创建Vue工程后,并导入element ui和axios,添加连接后端项目的路径,把axios挂载到Vue

1.2. 前置路由守卫(所有路由跳转前核实一下身份)

//前置路由守卫--所有的路由跳转都先经过这里
    // to:即将要访问的路径  from:从哪里来 next:放行函数
  //解决登录之后关闭浏览器之后,还可以不用登录就能进入登录后的页面
  router.beforeEach((to, from, next) => {
    //如果是  登录页面 或者 token为真 就放行    其他情况强制跳转到登录页面
    const token = sessionStorage.getItem('token');
    if (to.path==="/login" || token){
      return next();
    }
    return next("/login");
  })

1.3. 请求过滤器(所有请求前都需携带令牌给后端)

//请求拦截器--每次请求前都会经过的
//这里的意义就是需要每次向后端发送请求都要携带者token令牌
axios.interceptors.request.use(function (config) {
  let token = sessionStorage.getItem('token');

  if (token){
    config.headers.token = token;
  }
  return config;
})

1.4. 响应拦截器(后端响应过来的json数据,根据code状态码判断成功/失败,并返回json数据给对应的请求,这里请求处只需要写对应的操作即可)

//设置响应拦截器
axios.interceptors.response.use(function (response) {
  if (response.data.code===200){
    Vue.prototype.$message.success(response.data.msg)
    return response;
  }else {
    Vue.prototype.$message.error(response.data.msg);
    return response;
  }
})

1.5. 页面布局路由导入跳转和请求

<template>
  <div class="home">
    <h1>主页页面</h1>
    <el-button type="success" @click="add()">增加</el-button>
    <el-button type="danger" @click="del()">删除</el-button>
    <el-button type="info" @click="update()">修改</el-button>
    <el-button type="primary" @click="sel()">查询</el-button>
    <el-button type="warning" @click="exp()">导出</el-button>
    <el-button icon="el-icon-switch-button" @click="outLogin()">退出</el-button>
  </div>
</template>

<script>
export default {
  name: 'home',
  data(){
  return{

  }
  },
  methods:{
    //退出
    outLogin(){
      this.$axios.post("/logout").then((res) => {
        sessionStorage.removeItem("token")
        this.$router.push("/login")
      })
    },
    //添加用户
    add(){
      this.$axios.get("/user/insert").then(res=>{

      })
    },
    //删除用户
    del(){
      this.$axios.get("/user/delete").then(res=>{

      })
    },
    //修改用户
    update(){
      this.$axios.get("/user/update").then(res=>{

      })
    },
    //查询
    sel(){
      this.$axios.get("/user/select").then(res=>{

      })
    },
    //导出
    exp(){
      this.$axios.get("/user/export").then(res=>{

      })
    }
  },
}
</script>
<style>
.home{
  margin: auto;
  text-align: center;
}
</style>

2. 后端准备工作

2.1. JWT工具类,客户端与服务器通信,都要带上jwt,放在http请求的头信息中

2.1.1. 引入jar
<!--引入jwt的依赖-->
<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>4.4.0</version>
</dependency>
2.1.2. 创建jwt的工具类

①创建令牌---②校验令牌---③根据token获取自定义的信息

package com.wjy.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Verification;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JWTUtil {
    private static final String SECRET = "wjyGyh";
    //通过jwt创建token令牌
    public static String createToken(Map<String,Object> map){
        Map<String, Object> head = new HashMap<>();
        head.put("alg", "HS256");
        head.put("typ", "JWT");

        Date date = new Date();//当前时间--发布时间
        Calendar instance = Calendar.getInstance();//获取当前时间
        instance.set(Calendar.SECOND,7200);//当前时间的基础上添加2个小时
        Date time = instance.getTime();

        return JWT.create()
        .withHeader(head)//头部信息
        .withIssuedAt(date)//发布日期
        .withExpiresAt(time)//过期时间
        .withClaim("userinfo",map)//存放用户信息--设置个人信息
        .sign(Algorithm.HMAC256(SECRET));//签名
    }

    //校验token
    public static boolean verify(String token){
        Verification require = JWT.require(Algorithm.HMAC256(SECRET));
        try {
            require.build().verify(token);
            return true;
        } catch (JWTVerificationException e) {
            System.out.println("token错误,校验失败");
            return false;
        }
    }

    //根据token获取自定义的信息
    public static Map<String,Object> getTokenInfo(String token,String key){
        return JWT.require(Algorithm.HMAC256(SECRET))
        .build()
        .verify(token)
        .getClaim(key)
        .asMap();
    }
}

2.2. 加密、认证、授权、权限管理

(包含了对密码加密、用户认证授权、登录前后的权限设置==》开启允许跨域

由于都是无返回值类型的,所有使用到了fastjson)

package com.wjy.config;

import com.alibaba.fastjson2.JSON;
import com.wjy.filter.LoginFilter;
import com.wjy.service.MyUserDetailService;
import com.wjy.util.JWTUtil;
import com.wjy.vo.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Configuration
//如果springboot的版本2.7.0以上有其他的写法
public class MySercurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private StringRedisTemplate redisTemplate;

    //密码编码器--会自动加密
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private MyUserDetailService myUserDetailService;
    //用户认证和授权
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService);
    }

    @Autowired
    private LoginFilter loginFilter;
    //登录前后的权限设置
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //把自定义的过滤器放在UsernamePasswordAuthenticationFilter之前
        http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);

        //登录页面
        http.formLogin()
                //登录页面
                .loginPage("/login.html")
                //登录成功后跳转的页面
                .loginProcessingUrl("/login")
                //登录成功后跳转的页面--必须都是Post请求
                //.successForwardUrl("/success")
                .successHandler(successHandler())
                //登录失败后跳转的页面
                //.failureForwardUrl("/error")
                .failureHandler(failureHandler())
                //上面的页面请求无需认证--无需权限认证特权
                .permitAll();

        //退出登录--通过登录时候token令牌存入redis中,这里从头中拿到token,如何删除redis中的token
        http.logout(item->{
            item.logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();
                String token = httpServletRequest.getHeader("token");

                    //如果token验证成功
                    //删除redis中的token
                    redisTemplate.delete("login"+token);
                    //返回json数据
                    R r = new R(200, "退出成功", null);
                    String jsonString = JSON.toJSONString(r);
                    writer.println(jsonString);
                    writer.flush();
                    writer.close();

            });
        });
        
        //权限不足跳转的页面
       // http.exceptionHandling().accessDeniedPage("/error.html");
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());

        //如果使用的登录页面不是自己的--禁止跨越伪造请求的过滤器
        http.csrf().disable();

        //security登录允许跨域
        http.cors();

        //其他所有请求都需要认证
        http.authorizeRequests()
                .anyRequest()
                .authenticated();
    }

    //登录成功后给前端返回的json数据--并存到redis中
    private AuthenticationSuccessHandler successHandler() {
        return (httpServletRequest, httpServletResponse, authentication)->{
            //设置响应的编码
            httpServletResponse.setContentType("application/json;charset=utf-8");
            //获取输出对象
            PrintWriter writer = httpServletResponse.getWriter();
            //封装map数据
            Map<String, Object> map = new HashMap<>();
            //①存放用户名
            map.put("username", authentication.getName());
            //获取权限
            List<String> collect = authentication.getAuthorities()
                    .stream()
                    .map(GrantedAuthority::getAuthority).collect(Collectors.toList());
            //②存放权限码
            map.put("permissions", collect);
            //1.生成token
            String token = JWTUtil.createToken(map);

            //存放在redis中
            redisTemplate.opsForValue().set("login"+token,"");

            //2.放入token,返回json数据
            R r = new R(200, "登录成功", token);
            //转为json数据
            String jsonString = JSON.toJSONString(r);
            //给前端判断的依据
            writer.println(jsonString);
            //刷新流
            writer.flush();
            //关闭流
            writer.close();
        };
    }

    //登录失败后给前端返回的json数据
    private AuthenticationFailureHandler failureHandler() {
        return (httpServletRequest, httpServletResponse, e)->{
            //设置响应的编码--->获取输出对象
          httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            R r = new R(500, "登录失败", e.getMessage());
            //转为json数据-->给前端判断的依据-->刷新流-->关闭流
            String jsonString = JSON.toJSONString(r);
            writer.println(jsonString);
            writer.flush();
            writer.close();
        };
    }

    //权限不足后给前端返回的json数据
    private AccessDeniedHandler accessDeniedHandler() {
        return (httpServletRequest, httpServletResponse, e)->{
            //设置响应的编码--->获取输出对象
            httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            //创建R对象 并转换成json数据给前端 判断作为的依据-->刷新流-->关闭流
            R r = new R(403, "权限不足", e.getMessage());
            String jsonString = JSON.toJSONString(r);
            writer.println(jsonString);
            writer.flush();
            writer.close();
        };
    }
}

未登录--自定义顾虑器

package com.wjy.filter;

import com.alibaba.fastjson.JSON;
import com.wjy.util.JWTUtil;
import com.wjy.vo.R;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component//交于spring容器管理
public class LoginFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setContentType("application/json;charset=utf-8");
        //获取请求路径
        String path = request.getRequestURI();
        //获取请求方式
        String method = request.getMethod();
        //判断请求路径是否为登录路径--是的话放行
        if ("/login".equals(path) && "POST".equals(method)){
            filterChain.doFilter(request,response);
            return;
        }

        //1.获取token令牌--从请求头中获取
        String token = request.getHeader("token");
        //2.判断token是否为空
        //①token为空
        if (StringUtils.isEmpty(token)){
            R r = new R(500, "未登录", null);
            PrintWriter writer = response.getWriter();
            String jsonString = JSON.toJSONString(r);
            writer.write(jsonString);
            writer.flush();
            writer.close();
            return;
        }
        //②token不为空或者redis中不存在token--验证token失败的情况(token不正确)
        if (!JWTUtil.verify(token) || !redisTemplate.hasKey("login"+token)){
            R r = new R(500, "token失效,登录失败", null);
            PrintWriter writer = response.getWriter();
            String jsonString = JSON.toJSONString(r);
            writer.write(jsonString);
            writer.flush();
            writer.close();
            return;
        }
        //③token不为空--验证token成功--获取token中的信息
        //获取token中的信息
        SecurityContext context = SecurityContextHolder.getContext();
        //--从JWT的工具类中获取
        Map<String, Object> userinfo = JWTUtil.getTokenInfo(token, "userinfo");
        //获取用户名
        Object username = userinfo.get("username");
        //获取权限码-->并转成需要的集合格式类型
        List<String> permissions = (List<String>) userinfo.get("permissions");
        List<SimpleGrantedAuthority> collect = permissions.stream()
                .map(item -> new SimpleGrantedAuthority(item))
                .collect(Collectors.toList());
        //创建token
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, collect);
        //将token放入上下文
        context.setAuthentication(authenticationToken);

        //④验证token成功--放行
        filterChain.doFilter(request,response);
    }
}

2.3. 跨域配置类

package com.wjy.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//跨域配置--允许跨域全局--自己定义的
@Configuration
public class CorsConfig implements WebMvcConfigurer {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //*全部,所有的意思
        registry.addMapping("/**")// 所有接口
                //是否发送Cookie
                .allowCredentials(true)// 是否发送 Cookie
                //放行哪些原始域
                .allowedOrigins("*")// 支持域--之后改成自己服务器的地址
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})// 支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

3. 业务层--登录

package com.wjy.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wjy.entity.User;
import com.wjy.mapper.PermissionMapper;
import com.wjy.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据用户名查询用户信息--username必须唯一
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userMapper.selectOne(wrapper);
        //判断用户是否存在
        if (Objects.nonNull(user)){
            //查询当前用户具有的权限
            List<SimpleGrantedAuthority> collection = permissionMapper.selectByUserId(
                    user.getUserid())//根据用户id查询权限
                    .stream()//转换流
                    .map(p -> new SimpleGrantedAuthority(p.getPercode()))//把每次查询的权限码封装成SimpleGrantedAuthority
                    .collect(Collectors.toList());//转换为集合
            return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getUserpwd(),collection);
        }
        return null;
    }
}

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

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

相关文章

C++密码管理器

先问一句 最近有几个关注我的原力等级为0或-1&#xff0c;文章全是转载&#xff0c;转载时间基本都在2021年&#xff0c;而且关注了很多人&#xff0c;这些是僵尸粉吗&#xff1f; 文末有投票&#xff0c;麻烦参与一下谢谢 实现功能列表 暂时还没做加密功能 打算用openssl/a…

C++ STL初阶(9):list 中关于reverse_iterator的实现

在完成vector和list的iterator相关部分的实践后来完成反向迭代器的实现 1. list的反向迭代器 书接上回&#xff0c;反向迭代器应当重新封装一个类。 反向迭代器和正向迭代器最大的区别就是&#xff0c;反向迭代器是倒着走的&#xff0c;所以最核心的逻辑就是将封装成-- 注意&am…

数字化转型-成就智慧智慧企业

数字化转型是企业迈向智慧化发展的关键路径&#xff0c;通过将先进的数字技术融入企业核心业务&#xff0c;构建智能化、数据驱动的运营模式&#xff0c;实现业务的全面升级与优化。智慧企业的实现依托于几个核心要素&#xff1a;首先是数字基础设施的建设&#xff0c;包括云计…

浅述TSINGSEE青犀EasyCVR视频汇聚平台与海康安防平台的区别对比

在我们的很多项目中都遇到过用户的咨询&#xff1a;TSINGSEE青犀EasyCVR视频汇聚平台与海康平台的区别在哪里&#xff1f;确实&#xff0c;在安防视频监控领域&#xff0c;EasyCVR视频汇聚平台与海康威视平台是两个备受关注的选择。它们各自具有独特的功能和优势&#xff0c;适…

RSS 源:在信息洪流中找回你的时间掌控权

简单介绍了 RSS 后&#xff0c;那么关键的一步就是建立好自己的 RSS 源了。 并不是所有平台都会提供 RSS 源&#xff0c;因此我们也没办法直接去订阅。 目前使用 RSS 的难题之一就是 RSS 源的匮乏&#xff0c;是无数人重新拥抱 RSS 的第一大障碍。 那么&#xff0c;如何去找…

全球化浪潮下的数据库革新:嘉里物流 TiDB 实践价值的设想

导读 本文来自 TiDB 社区武汉站——嘉里物流架构团队负责人肖飞老师的演讲《嘉里物流 & TiDB 在全球化业务场景中应用设想》。本次分享探讨了嘉里物流在全球化扩展中&#xff0c;将如何通过 TiDB 的强大功能应对海量数据挑战&#xff0c;优化技术架构&#xff0c;并提升决…

Adaptive Subgraph Neural Networkwith Reinforced Critical Structure Mining

1 Introduction graph mining area: 图挖掘领域 图具有广泛的局部结构&#xff1a;从节点、模体&#xff08;motifs&#xff09;到子图&#xff08;subgraph&#xff09; 主流研究表明&#xff1a;图的重要特征和突出模式是通过主要由一些关键局部结构&#xff08;如模体和子图…

html+css 实现hover 翻转按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目…

NCL的安装和运行;气象数据可视化;散点图、直方图、等值线图、箭头图、任意折线和任意图形、非规则网格、图形叠加、组图的绘制

NCAR Command Language&#xff08;NCL&#xff09;是由美国大气研究中心&#xff08;NCAR&#xff09;推出的一款用于科学数据计算和可视化的免费软件。它有着非常强大的文件输入和输出功能&#xff0c;可读写netCDF-3、netCDF-4 classic、HDF4、binary、ASCII数据&#xff0c…

LVS实验的三模式总结

文章目录 LVS的概念叙述NAT工作模式实战案例**思想&#xff1a;**NAT工作模式的优点NAT工作模式的缺点 NAT工作模式的应用场景大致配置 route&#xff1a;打开路由内核功能 部署DR模式集群案例工作思想&#xff1a;大致工作图如下思路模型 具体配置与事实步骤补充 防火墙标签解…

RCE漏洞复现

PHP命令执行常用函数 回调函数必须是命令执行和代码执行的函数&#xff0c;有两个条件 必须是函数&#xff0c;而且需要有函数运行的参数 危害&#xff1a;可以直接删除文件&#xff0c;添加文件&#xff0c;甚至可以添加用户 system --执行外部程序&#xff0c;并且显示输…

Ubuntu操作系统的基础操作和设置(详细且全面)(1)

前言 当Ubuntu系统被搭建完成以后&#xff0c;为了方便大家更容易上手&#xff0c;所以对常见的基础操作和设置进行讲解 1.支持中文显示&#xff0c;中文输入设置 1.1&#xff1a;支持中文显示 Ubuntu操作系统默认显示和输入的语言是英文。所以&#xff0c;如果你的英…

《虚拟之旅:开启无限可能的机器世界》简介:

1.Ubonto的介绍&#xff1a; Ubuntu 是一个流行的开源操作系统&#xff0c;基于 Linux 内核。 它具有以下一些特点和优势&#xff1a; 开源免费&#xff1a;任何人都可以免费使用、修改和分发。丰富的软件库&#xff1a;通过软件包管理器可以方便地安装各种应用程序。良好的…

Linux系统移植——开发板烧写(二)

目录&#xff1a; 目录&#xff1a; 一、什么是EMMC分区&#xff1f; 1.1 eMMC分区 1.2 分区的管理 二、相关命令介绍&#xff1a; 2.1 mmc 2.1.1 主要功能 2.1.2 示例用法 2.2 fdisk 2.2.1 基本功能 2.2.2 交互模式常用命令 2.2.3 注意事项 三、U-BOOT烧写 3.1 mmc命令 3.2 f…

Java并发面试题汇总

文章目录 线程什么是线程和进程?请简要描述线程与进程的关系,区别及优缺点?程序计数器、虚拟机栈、虚拟机栈、堆和方法区如何创建线程?线程的生命周期什么是线程上下文切换?Thread#sleep() 方法和 Object#wait() 方法对比为什么 wait() 方法不定义在 Thread 中?为什么 sle…

【解压即玩】PC端最好用最漂亮的前端CoinOPS整合包186G 复古带遮罩和滤镜,怀旧拉满

这是大神做的一个整合包&#xff0c;让游戏界面更加的漂亮&#xff0c;如图&#xff0c;下面是游戏选择画面&#xff0c;右侧是滚动的圆盘&#xff0c;左侧显示游戏的画面&#xff1a; 实际游戏时的界面是这样的&#xff1a; 应当是目前最漂亮的游戏界面了。之前有人说在电脑上…

sp eric靶机

扫描IP 端口扫描 nmap 192.168.111.146 -p- -sV 目录扫描 # 使用命令 dirsearch -u "http://192.168.111.146" 访问靶机IP地址 拼接访问 admin.php &#xff0c;发现登录框界面&#xff0c;尝试sql注入&#xff0c;弱口令等&#xff0c;没有结果 看看 .git &#…

【C语言篇】C语言常考及易错题整理DAY2

文章目录 C语言常考及易错题整理选择题编程题至少是其他数字两倍的最大数两个数组的交集图片整理寻找数组的中心下标多数元素除自身以外数组的乘积不使用加减乘除求两个数的加法 C语言常考及易错题整理 选择题 下列 for 循环的次数为&#xff08; &#xff09; for(int i 0…

高可用keepalived详解---干货满满(企业应用示例)

目录 一、master/master 的 Keepalived 双主架构 1.1 ka1部署 1.2 ka2部署 1.3 重启测试 二、实现ipvs高可用 (keepalivedlvs) 2.1 ipvs的相关配置 2.1.1 虚拟服务器配置架构 2.1.2 virtual server &#xff08;虚拟服务器&#xff09;的定义格式 2.1.3 虚拟服务器…

四十、大数据技术之Kafka3.x(3)

&#x1f33b;&#x1f33b; 目录 一、Kafka Broker1.1 Kafka Broker工作流程1.1.1 Zookeeper 存储的Kafka信息1.1.2 Kafka Broker 总体工作流程1.1.3 Broker 重要参数 1.2 生产经验——节点服役和退役1.2.1 服役新节点1.2.2 退役旧节点 1.3 Kafka 副本1.3.1 副本基本信息1.3.2…