springSecurity自定义登陆接口和JWT认证过滤器
下面我会根据该流程图去自定义接口:
我们需要做的任务有:
登陆:1、通过ProviderManager的方法进行认证,生成jwt;2、把用户信息存入redis;3、自定义UserDetailsService实现到数据库查询数据的方法。
校验:自定义一个jwt认证过滤器,其实现功能:获取token;解析token;从redis获取信息;存入SecurityContextHolder。
登陆:
图中的 5.1步骤是到内存中查询用户信息,而我们需要的是到数据库中查询。而图中查询用户信息是调用loadUserbyUsername方法实现的。
所以我们需要实现UserDetailsService接口并重写该方法:(下面案例中我用的mybatis plus实现的查询数据库)
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;//loadUserByUsername方法即为流程图中查询用户信息的方法。@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户信息LambdaQueryWrapper<User> queryWrapper= new LambdaQueryWrapper<>();queryWrapper.eq(User::getUserName,username);User user = userMapper.selectOne(queryWrapper);//如果没有查询到用户if(Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}//封装为UserDetails类型返回return new LoginUser(user);}
}
我们先写好登陆功能的controller层代码:
@RestController
public class LoginController {@Autowiredprivate LoginService loginService;@PostMapping("/user/login")public ResponseResult login(@RequestBody User user){//登陆return loginService.login(user);}
我们需要让springSecurity对该登陆接口放行,不需要登陆就能访问。在登陆service层接口中需要通过AuthenticationManager的authenticate方法进行用户认证,我们先在SecurityConfig中把AuthenticationManager注入容器。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Override@Bean //(name = "") //获取AuthenticationManager的bean,因为现在只有这一个AuthenticationManager,所以不写也没事。protected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();}//放开接口@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf,csrf为跨域策略,不支持post.csrf().disable()//不通过session获取SecurityContext 前后端分离时session不可用.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()//对于登陆接口,允许匿名访问,登陆之后不允许访问,只允许匿名的用户,可以防止重复登陆。.antMatchers("/user/login").anonymous() //permitAll() 登录能访问,不登录也能访问,一般用于静态资源js等//除了上面外,所有请求需要鉴权认证.anyRequest().authenticated();//authenticated():任意用户,认证后都可访问。}}
然后我们去修改登陆接口的service层实现类代理:
@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisCache redisCache;//登陆@Overridepublic ResponseResult login(User user) {//获取AuthenticationManager的authenticate方法进行认证。//通过SecurityConfig获取AuthenticationManager//创建Authentication,第一个参数为认证主体,没有的话传用户名,第二个参数传密码UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());//需要Authentication参数(上面)Authentication authenticate = authenticationManager.authenticate(authenticationToken);//这样让ProviderManager调用UserDetailsService类中的loadUserByUsername方法完成认证//如果认证不通过,authenticate为null//认证没通过,给出提示if(Objects.isNull(authenticate)){throw new RuntimeException("登陆失败");}//认证通过,使用userid生成jwt,jwt存入ResponseResult返回//获取userIdLoginUser loginUser = (LoginUser) authenticate.getPrincipal();String userId = loginUser.getUser().getId().toString();String jwt = JwtUtil.createJWT(userId);Map<String,String> map = new HashMap<>();map.put("token",jwt);//完整信息存入redis,userid作keyredisCache.setCacheObject("login:"+userId,loginUser);return new ResponseResult(200,"登陆成功",map);}
}
springSecurity流程图中是通过获取AuthenticationManager的authenticate方法进行认证。通过SecurityConfig中注入的bean获取AuthenticationManager。
authenticationManager的authenticate方法需要一个Authentication实现类参数,所以我们创建一个UsernamePasswordAuthenticationToken实现类
其中的JwtUtil.createJWT(userId);方法,是我自定义的根据userId生成JWT的工具类方法:
public class JwtUtil {//有效期为public static final Long JWT_TTL = 60*60*1000L;//一个小时//设置密钥明文 。随便定义,方便记忆和使用即可,但需要长度要为4的倍数。public static final String JWT_KEY = "jyue";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}//生成JWT//subject为token中存放的数据(json格式)public static String createJWT(String subject){JwtBuilder builder = getJwtBuilder(subject, null, getUUID());//设置过期时间return builder.compact();}public static JwtBuilder getJwtBuilder(String subject,Long ttlMillis,String uuid){SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey=generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis ==null){ttlMillis=JwtUtil.JWT_TTL;}long expMills=nowMillis+ttlMillis;Date expDate = new Date(expMills);return Jwts.builder().setId(uuid) //唯一id.setSubject(subject) //主题 可以是JSON数据.setIssuer("jy") //签发者,随便写.setIssuedAt(now) //签发时间.signWith(signatureAlgorithm,secretKey) //使用HS256对称加密算法签名,第二个参数为密钥。.setExpiration(expDate);}public static SecretKey generalKey(){byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKeySpec key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");return key;}public static Claims parseJWT(String jwt)throws Exception{SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}
}
redisCache也为自定义的redis工具类:
@SuppressWarnings(value = {"unchecked","rawtypes"})
@Component
public class RedisCache {@Autowiredpublic RedisTemplate redisTemplate;//缓存对象//key 缓存键值//value 缓存值public <T> void setCacheObject(final String key,final T value){redisTemplate.opsForValue().set(key,value);}//获取缓存的基本对象// key 键值// return 缓存键对应的数据public <T>T getCacheObject(final String key){ValueOperations<String,T> operation = redisTemplate.opsForValue();return operation.get(key);}
}
JWT认证:
@Component //继承这个实现类,保证了请求只会经过该过滤器一次
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//首先需要从请求头中获取tokenString token = request.getHeader("token");//判断token是否为Nullif(!StringUtils.hasText(token)) {//token没有的话,直接放行,抛异常的活交给后续专门的过滤器。filterChain.doFilter(request, response);//响应时还会经过该过滤器一次,直接return,不能执行下面的解析token的代码。return;}//如何不为空,解析token,获得了UserIdString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();} catch (Exception e) {e.printStackTrace();//token格式异常,不是正经tokenthrow new RuntimeException("token非法");}//根据UserId查redis获取用户数据String key = "login:"+userId;LoginUser loginUser = redisCache.getCacheObject(key);if(Objects.isNull(loginUser)){throw new RuntimeException("用户未登录");}//然后封装Authentication对象存入SecurityContextHolder// 因为后续的过滤器会从SecurityContextHolder中获取信息判断认证情况,而决定是否放行。// 这里用UsernamePasswordAuthenticationToken三个参数的构造函数,是因为其能设置已认证的状态(因为已经从redis中获取了信息,确认是认证的了)//第一个参数为用户信息,第三个参数为权限信息,目前还没获取,先填nullUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null);//默认SecurityContextHolder是ThreadLocal线程私有的,这也是为什么上面要用UsernamePasswordAuthenticationToken三个参数的构造方法SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request,response);}
}
这样登陆后用户发送请求,后端会先从请求头中获取token,然后解析出userId,然后从redis中查询该用户详细信息。然后把用户的详细信息存入UsernamePasswordAuthenticationToken三个参数的构造函数,是因为其能设置已认证的状态(因为已经从redis中获取了信息,确认是认证的了),然后把UsernamePasswordAuthenticationToken存入SecurityContextHolder。
因为后续的过滤器会从SecurityContextHolder中获取信息判断认证情况,而决定是否放行。
相关文章:
springSecurity自定义登陆接口和JWT认证过滤器
下面我会根据该流程图去自定义接口: 我们需要做的任务有: 登陆:1、通过ProviderManager的方法进行认证,生成jwt;2、把用户信息存入redis;3、自定义UserDetailsService实现到数据库查询数据的方法。 校验&a…...
Spring Boot日志:从Logger到@Slf4j的探秘
写在前面 Hello大家好,今日是2024年的第一天,祝大家元旦快乐?? 2024第一篇文章从SpringBoot日志开始 文章目录 一、前言二、日志有什么用?三、日志怎么用?四、自定义日志打印 ?? 常见日志框架说明4.1 在程序中得到?志对象【…...
使用 LabVIEW 与 PLC 通信的方式
要将 PLC 与 LabVIEW 或其他 NI 产品进行通信,首先需要明确 PLC 支持的通信协议和接口类型。NI 提供了多种方案,包括 OPC 服务器、Modbus、Ethernet/IP 和其他工业通信协议。下面将详细介绍这些方法,并进行比较分析,帮助你选择最适…...
python录制鼠标键盘操作循环播放
依赖 pip install pynput 程序: from pynput import mouse, keyboard import time import threading# 用于存储录制的鼠标和键盘事件 mouse_events [] keyboard_events []# 定义事件处理函数# 处理鼠标事件 def on_move(x, y):mouse_events.append((move, x, y))def on_cl…...
开发者如何使用GCC提升开发效率Opencv操作
看此篇前请先阅读 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144216351?spm=1001…...
异常与文件
目录 1.异常 1.1.概念 1.2.常见异常 1.3.异常处理方式 1.3.1.try except 1.3.2.try except else 1.3.3.try except else finally 2.文件 2.1.文件分类 ps:python 程序的数据保存在哪里? 2.2.常见的文件类型 2.3.python 操作文件的函数 2.3.1.读取文件…...
【C语言】完成程序设计填空
文章目录 1、请阅读下面的程序,在空白处填写正确的代码,要求各在一行从头开始输出m和n的值。2、求100~599之间的所有水仙花数,即各位数字的立方和恰好等于该数本身的数。3、以下程序的功能是:将值为三位正整数的变量x中的数值按照个位、十位、百位的顺序 拆分并输出。请填空…...
西湖大学:LLM零样本推理任务校准
📖标题:Task Calibration: Calibrating Large Language Models on Inference Tasks 🌐来源:arXiv, 2410.18764 🌟摘要 🔸大型语言模型(LLM)在推理任务上表现出令人印象深刻的零样本…...
windows下Qt5自动编译配置QtMqtt环境(11)
文章目录 [toc]1、概述2、准备1.1 下载源码1.2 配置环境1.3 解释原理 3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配…...
每天五分钟深度学习:神经网络的前向传播的计算(多样本)
本文重点 前面我们学习了单样本的前向传播,本文我们学习多样本的前向传播,我们先来回忆一下,神经网络的单样本的前向传播的向量化的方式: m个样本依次进行前向传播 这里我们说明一下符号: 我们使用(m)表示第m个样本,用[m]表示神经网络的第m层 a[2](i) 表示第i个样本计…...
基于 NXP S32K312+FS23 的汽车通用评估板方案
S32K3 系列是 NXP 推出的面向汽车电子和工业应用的微控制器,基于 ARMCortex-M7 内核,支持单核、双核和锁步内核配置。S32K3 系列具有内核、内存和外设数量方面的可扩展性,符合 ISO26262 标准,能达到 ASIL B/D 安全等级,…...
11进阶篇:专业课论文阅读方向指南(2025版)
文章目录 第一个检索式:图情档核心期刊(北大 + CSSCI)发文情况研究方法类关键词研究主题类关键词论文阅读建议第二个检索式:川大公共管理学院在核心期刊(北大 + CSSCI)的发文情况研究方法类关键词研究主题类关键词特点关键词与2024年972(现815)两道题目的映射情况815信…...
Qt之第三方库QXlsx使用(三)
Qt开发 系列文章 - QXlsx(三) 目录 前言 一、Qt开源库 二、QXlsx 1.QXlsx介绍 2.QXlsx下载 3.QXlsx移植 4.修改项目文件.pro 三、使用技巧 1.写入数据 2.读出数据 总结 前言 Qt第三方控件库是指非Qt官方提供的、用于扩展Qt应用程序功能的控件…...
第145场双周赛: 使数组的值全部为 K 的最少操作次数、破解锁的最少时间 Ⅰ、使两个整数相等的位数操作、统计最小公倍数图中的连通块数目
Q1、使数组的值全部为 K 的最少操作次数 1、题目描述 给你一个整数数组 nums 和一个整数 k 。 如果一个数组中所有 严格大于 h 的整数值都 相等 ,那么我们称整数 h 是 合法的 。 比方说,如果 nums [10, 8, 10, 8] ,那么 h 9 是一个 合法…...
AJAX三、XHR,基本使用,查询参数,数据提交,promise的三种状态,封装-简易axios-获取省份列表 / 获取地区列表 / 注册用户,天气预报
一、XMLHttpRequest基本使用 XMLHttpRequest(XHR)对象用于与服务器交互。 二、XMLHttpRequest-查询参数 语法: 用 & 符号分隔的键/值对列表 三、XMLHttpRequest-数据提交 核心步骤 : 1. 请求头 设置 Content-Type 2. 请求体 携带 符合要求 的数…...
Android期末复习题
1.如何搭建Android开发环境? 答案:搭建Android开发环境需要以下几个步骤: (1)下载和安装JDK (2)配置PATH环境变量 (3)下载和安装Android Studio (4)创建A…...
《蓝桥杯比赛规划》
一、比赛简介 蓝桥杯全国软件和信息技术专业人才大赛是一项具有较高影响力的编程竞赛,旨在促进软件和信息技术领域专业技术人才的培养,提升高校毕业生的就业竞争力。比赛涵盖了多个编程语言和专业方向,包括 C/C、Java、Python 等。 二、目标…...
三、Zookeeper
Zookeeper 三、Zookeeper3.1什么是zookeeper?3.2为什么需要zookeeper3.3Zookeeper基本运行流程3.4Zookeeper数据模型3.5Zookeeper主要角色3.6Zookeeper工作原理3.7Zookeeper节点数据操作流程三、Zookeeper 3.1什么是zookeeper? ZooKeeper是一个分布式的,开放源码的分布式应…...
Wireshark数据抓包分析之传输层协议(TCP协议)
根据实验环境,本实验的步骤如下: 1.在测试环境使用发包工具和Wireshark抓取TCP三次握手和四次断开的数据包。 2.详细分析TCP协议的三次握手以及四次断开。 任务描述:安装发包工具,并配置TCP客户端,服务端࿰…...
用ai做机器视觉的事情
cnn(卷积神经网络)是典型的ai算法。 我们已经cnn实现像机器视觉中形状匹配的功能,因为使用了roi抠图匹配,所以就叫做roicnn,以区分整图匹配。下面是roicnn笔记总结: 20241022,roicnn搞定&…...
LLM - 开源视觉多模态 LLaVA-CoT(o1) 深度推理模型 测试与源码 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144304351 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 LLaVA-…...
qtcanpool 知 10:包管理雏形
文章目录 前言痛点转机雏形实践后语 前言 曾听闻:C/Qt 没有包管理器,开发起来太不方便。这是一个有过 node.js 开发经验的人对 Qt 的吐槽。 确实,像 python、golang、node.js 这些编程语言都有包管理器,给用户带来了极佳的开发体…...
[保姆式教程]使用目标检测模型YOLO11 OBB进行旋转目标检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)
之前写了一个基于YOLOv8做旋转目标检测(OBB)的文章,内容写得不够好,内容也有些杂乱无序。现如今YOLO已经更新到11了,数据集也集齐了无人机和卫星的农业大棚,所以这次就写一个基于YOLO11 OBB的农业大棚旋转检…...
MySQL 权限管理分配详解
MySQL 权限管理分配详解 MySQL权限系统的工作原理权限表的存取用户通过权限认证、进行权限分配的流程账号管理我们常用的授权all privileges到底有哪些权限呢?以及带来的安全隐患有哪些?创建账户的时候最好分配指定的权限,这样子安全也高管理…...
【期末速成】《微机原理与接口技术》知识点总结
文章目录 前言第一、二章 接口技术概述1. 接口的定义*2. 接口功能特点*3. 接口的分类*4. 接口中的传输信息及其组成5. 接口的编址与译码*6. CPU 与外设之间的数据传送方式* 第三章 总线1. 总线(BUS)的定义*2. 总线的标准3. 采用标准总线的优点*4. 总线的…...
华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数
华为交换机WEB操作 使用的是真机S5735,目前主流的版本都适用(V1R5~V2R1的就不在列了,版本太老了,界面完全不一样,这里调试线接的console口,电脑的网络接在ETH口) 「模拟器、工具合集」复制整段内…...
【Elasticsearch】初始化默认字段及分词
1、添加分词插件 1)在线安装 执行命令 需要指定相同的版本 bin/elasticsearch-plugin.bat install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.24 2)离线安装 将安装包解压到 /plugins 目录下 安装包可以从对应的资源处下载 启动成…...
asdf-java配置
asdf list all java 无结果 asdf list all java 显示结果 No compatible versions available 解决方案 参考 执行 cp ~/.asdf/plugins/java/data/jdk-macosx-x86_64-ga.tsv $TMPDIR/asdf-java-$(whoami).cache/releases-macosx-x86_64.tsv 在此执行 asdf list all java 就可…...
2-2-18-14 QNX系统架构之 TCP/IP 网络
阅读前言 本文以QNX系统官方的文档英文原版资料为参考,翻译和逐句校对后,对QNX操作系统的相关概念进行了深度整理,旨在帮助想要了解QNX的读者及开发者可以快速阅读,而不必查看晦涩难懂的英文原文,这些文章将会作为一个…...
RabbitMQ延迟消息的实现
RabbitMQ延迟队列的实现 延迟消息是什么延迟消息的实现死信交换机代码实现 延迟消息插件 延迟消息是什么 延迟消息是将消息发送到MQ中,消费者不会立即收到消息,而是过一段时间之后才会收到消息,进行处理。在一些业务中,可以用到延…...
Docker 安装 中文版 GitLab
Docker 安装系列 安装GitLab、解决服务器内存不足问题、使用域名/IP地址访问项目 1、拉取 [rootTseng ~]# docker pull twang2218/gitlab-ce-zh:latest latest: Pulling from twang2218/gitlab-ce-zh 8ee29e426c26: Pull complete 6e83b260b73b: Pull complete e26b65fd11…...
Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】
anaconda可以提供多个独立的虚拟环境,方便我们学习深度学习(比如复现论文); Pycharm编辑器可以高效的编写python代码,也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程: 1.Anaconda安装 下载Ana…...
springboot整合canal
学习链接 Cannal项目地址 SpringBoot整合Canal实现数据同步到ElasticSearch - 原文地址 Spring Boot整合canal实现数据一致性解决方案解析-部署实战 Java:SpringBoot整合Canal实现数据同步 docker环境安装mysql、canal、elasticsearch,基于binlog利…...
8.在 Vue 3 中使用 OpenLayers 加载天地图示例(多种形式)
前言 OpenLayers 是一个强大的开源地图框架,可以轻松实现地图加载与操作。而 Vue 3 则通过 Composition API 提供了更加简洁和灵活的开发体验。本文将介绍如何在 Vue 3 中结合 OpenLayers 实现对天地图的加载,包括矢量地图、卫星地图以及中文和英文标记等…...
如何设置 Java 开发环境
如果你在这里,可能是想学习如何为 Java 开发设置环境。第一步是安装 SDK(软件开发工具包),它是一组由硬件和软件供应商提供的工具和库。 对于 Java,我们使用 JDK(Java 开发工具包)。JDK 是一组…...
MetaGPT 安装
1. 创建环境 conda create -n metagpt python3.10 && conda activate metagpt2. 可编辑方式安装 git clone --depth 1 https://github.com/geekan/MetaGPT.git cd MetaGPT pip install -e .3. 配置 metagpt --init-config运行命令,在C盘位置C:\Users\325…...
石岩湿地公园的停车场收费情况
周末石岩湿地公园停车场【967个】小车停车费封顶14元价格还行,我还记得2020年的时候湿地公园还是10元一天封顶。现在的收费情况也是可以的,尤其是周末停车比工作日停车便宜还是很得民心的哈。 车型 收费标准 小车 工作日 高峰时间8:00~20:00 首小时…...
v3账号密码登录随机图片验证码
安装插件 pnpm i identify --save图形验证码组件 <template><div class"s-canvas"><!-- 图形验证码的宽和高都来自于父组件的传值,若父组件没有传值,那么就按当前子组件的默认值进行渲染 --><canvas id"s-canvas&…...
mysql8 主从复制一直失败
问题描述: 开启同步后从服务器一直失败,报错如下: Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log …...
Java项目实战II基于微信小程序的消防隐患在线举报系统(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着城市化进程的加快&…...
【第二十四周】从大语言模型到多模态大模型的发展
摘要 大语言模型(Large Language Model, LLM)是指一类基于深度学习的人工智能系统,它们被设计用来理解和生成自然语言。这些模型通常是在大量的文本数据上进行训练的,通过学习文本中的模式和结构,它们能够执行各种各样…...
深入理解Java的 JIT(即时编译器)
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
数据库技术文档撰写:全方位剖析
在技术的浩瀚海洋中,一份优秀的技术文档宛如精准的航海图。它是知识传承的载体,是团队协作的桥梁,更是产品成功的幕后英雄。然而,打造这样一份出色的技术文档并非易事。你是否在为如何清晰阐释复杂技术而苦恼?是否纠结…...
设计模式之原型模式:深入浅出讲解对象克隆
~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” 原型模式概述 在我们的日常生活中,经常会遇到"复制"这样的场景。比如我们在准备文件时,常常会复印一份原件&a…...
centos 查看版本
在 CentOS 中,查看系统版本有多种方法。以下是几种常用的方法: 方法 1:使用 cat 命令查看 /etc/centos-release 文件 cat /etc/centos-release 这个文件包含了 CentOS 的版本信息。例如,输出可能是: CentOS Linux rel…...
如何本地存储中的文件路径
文章目录 1. 概念介绍2. 实现方法3. 示例代码我们在上一章回中介绍了"如何实现本地存储"相关的内容,本章回中将介绍如何实现文件存储.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在上一章回中介绍的本地存储只能存储dart语言中基本类型的数值,如果遇到…...
服务器加固
1.服务器密码复杂度 密码最小长度,密码复杂度策略 vim /etc/pam.d/system-auth --------------- #密码配置 #ucredit:大写字母个数;lcredit:小写字母个数;dcredit:数字个数;ocredit:…...
MongoDB change stream实战
什么是 Chang Stream Change Stream指数据的变化事件流,MongoDB从3.6版本开始提供订阅数据变更的功能。 Change Stream 是 MongoDB 用于实现变更追踪的解决方案,类似于关系数据库的触发器,但原理不完全相同: Change Stream 的实…...
TSWIKI知识库软件
TSWIKI 知识库软件介绍 推荐一个适合本地化部署、自托管的知识库软件 TSWIKI介绍 tswiki 是一个适合小团队、个人的知识库、资料管理的软件,所有数据均本地化存储。可以本地化、私有云部署,安装简单。在线预览。 主要功能说明 1、简化的软件依赖和安…...
【Linux课程学习】第十九弹---深入理解进程间通信---匿名管道,命名管道,多匿名管道的BUG
🎁个人主页:我们的五年 🔍系列专栏:Linux课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 Linux学习笔记: https://blog.csdn.n…...