Day3 权限管理

news/2024/5/17 13:48:55

Day3 权限管理

这里会总结构建项目过程中遇到的问题,以及一些个人思考!!
学习方法:
1 github源码 + 文档 + 官网
2 内容复现 ,实际操作

项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目

创建管理员服务模块

提供对角色和权限的管理— 操作数据库

  1. pom文件(父子关系、 依赖注入)
  2. 配置文件修改 nacos注册
  3. 服务和common接口

新增管理员


/*** 管理员实现类** @author bootsCoder* @date created on 2024/4/15*/
@DubboService
@Transactional
public class AdminServiceImpl implements AdminService {@Autowiredprivate AdminMapper adminMapper;@Overridepublic void add(Admin admin) {adminMapper.insert(admin);}@Overridepublic void update(Admin admin) {}@Overridepublic void delete(Long id) {}@Overridepublic Admin findById(Long id) {return null;}@Overridepublic Page<Admin> search(int page, int size) {return null;}@Overridepublic void updateRoleToAdmin(Long aid, Long[] rids) {}
}/*** 管理员服务** @author bootsCoder* @date created on 2024/4/15*/
public interface AdminService {/*** 新增管理员*/void add(Admin admin);/*** 更新管理员*/void update(Admin admin);/*** 删除管理员*/void delete(Long id);/*** 查找管理员*/Admin findById(Long id);/*** 新增管理员*/Page<Admin> search(int page, int size);/*** 更新角色*/void updateRoleToAdmin(Long aid, Long[] rids);
}/*** 管理员api** @author bootsCoder* @date created on 2024/4/15*/
@RestController
@RequestMapping("/admin")
public class AdminController {@DubboReferenceprivate AdminService adminService;@PostMapping("/add")public BaseResult add(@RequestBody Admin admin) {adminService.add(admin);return BaseResult.ok();}
}
image-20240415194505264

删除管理员

删除管理员时需要删除对应的角色


/*** 管理员的数据库映射类** @author bootsCoder* @date created on 2024/4/15*/
public interface AdminMapper extends BaseMapper<Admin> {/*** Deletes all roles associated with the specified administrator ID.** @param aid the administrator ID*/@Delete("DELETE FROM boots_admin_role WHERE aid = #{aid}")void deleteAdminAllRole(@Param("aid") Long aid);
}

查询管理员 – 编写多表联查

xml 格式,有时间研究一下 @Select 的方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bootscoder.shopping_admin_service.mapper.AdminMapper"><resultMap id="adminMapper" type="com.bootscoder.shopping_common.pojo.Admin"><id property="aid" column="aid"></id><result property="username" column="username"></result><collection property="roles" column="aid" ofType="com.bootscoder.shopping_common.pojo.Role"><id property="rid" column="rid"></id><result property="roleName" column="roleName"></result><result property="roleDesc" column="roleDesc"></result><collection property="permissions" column="rid" ofType="com.bootscoder.shopping_common.pojo.Permission"><id property="pid" column="pid"></id><result property="permissionName" column="permissionName"></result><result property="url" column="url"></result></collection></collection></resultMap><select id="findById" parameterType="long" resultMap="adminMapper">SELECT * FROM boots_adminLEFT JOIN boots_admin_role on boots_admin.aid = boots_admin_role.aidLEFT JOIN boots_role on boots_admin_role.rid = boots_role.ridLEFT JOIN boots_role_permission on boots_role.rid = boots_role_permission.ridLEFT JOIN boots_permission on boots_role_permission.pid = boots_permission.pidWHERE boots_admin.aid = #{aid}</select><insert id="addRoleToAdmin">INSERT INTO boots_admin_role values (#{aid},#{rid});</insert><select id="findAllPermission" parameterType="string" resultType="com.bootscoder.shopping_common.pojo.Permission">SELECT DISTINCT boots_permission.*FROMboots_adminLEFT JOIN boots_admin_role ON boots_admin.aid = boots_admin_role.aidLEFT JOIN boots_role on boots_admin_role.rid = boots_role.ridLEFT JOIN boots_role_permission on boots_role.rid = boots_role_permission.ridLEFT JOIN boots_permission on boots_role_permission.pid = boots_permission.pidWHERE boots_admin.username = #{username}</select>
</mapper>

这个真的是有一手了,我感觉得好好学,不开玩笑

分页查询管理员

 @GetMapping("/search")public BaseResult<Page<Admin>> search(int page, int size) {Page<Admin> adminPage = adminService.search(page, size);return BaseResult.ok(adminPage);}@Overridepublic Page<Admin> search(int page, int size) {return adminMapper.selectPage(new Page<>(page, size), null);}//在启动类配置分页@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
image-20240415204655342

修改管理员角色

修改管理员的角色,即修改boots_admin_role表中的记录。修改管理员角色时,先将管理员的所有角色删除,再将其新角色添加到boots_admin_role表中。

/*** 管理员实现类** @author bootsCoder* @date created on 2024/4/15*/
@DubboService
@Transactional //配置事务
public class AdminServiceImpl implements AdminService {@Override@Transactionalpublic void updateRoleToAdmin(Long aid, Long[] rids) {if (aid == null || aid <= 0) {//这个异常我想让我的异常捕获器捕捉到该怎么办呢?throw new IllegalArgumentException("Invalid administrator ID");}if (rids == null || rids.length == 0) {throw new IllegalArgumentException("Roles array must not be empty");}// 删除用户的所有角色adminMapper.deleteAdminAllRole(aid);// 重新添加管理员角色for (Long rid : rids) {adminMapper.addRoleToAdmin(aid, rid);}}
}

提问:

  1. 方法【updateRoleToAdmin】需要在Transactional注解指定rollbackFor或者在方法中显式的rollback。 why
  2. 类的@Transaction 注释和 方法的有什么不同
  3. how to add this exception in my own exception handler?

认真比对了一下参数,成功了

生成接口文档 – easyYAPi

连接前端工程 测试

image-20240416181600159

image-20240416182038506

修改角色? – > 如果用户本来没有角色需要添加怎么办?

修改逻辑错误

 @Overridepublic void updateRoleToAdmin(Long aid, Long[] rids) {if (aid == null || aid <= 0) {//这个异常我想让我的异常捕获器捕捉到该怎么办呢?throw new IllegalArgumentException("Invalid administrator ID");}// 删除用户的所有角色adminMapper.deleteAdminAllRole(aid);if (rids != null || rids.length > 0) {for (Long rid : rids) {// 重新添加管理员角色adminMapper.addRoleToAdmin(aid, rid);}}}

测试:
删除成功~
JDBC Connection [HikariProxyConnection@1234983148 wrapping com.mysql.cj.jdbc.ConnectionImpl@6fb35126] will be managed by Spring
= => Preparing: DELETE FROM boots_admin_role WHERE aid = ?
= = > Parameters: 33(Long)
<== Updates: 1

编写角色相关功能

和admin 类似 还是一样 最难的部分是xml中sql的编写和结果的封装

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bootscoder.shopping_admin_service.mapper.PermissionMapper"><delete id="deletePermissionAllRole" parameterType="long">DELETE FROM boots_role_permission WHERE pid = #{pid}</delete>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bootscoder.shopping_admin_service.mapper.RoleMapper"><resultMap id="roleMapper" type="com.bootscoder.shopping_common.pojo.Role"><id property="rid" column="rid"></id><result property="roleName" column="roleName"></result><result property="roleDesc" column="roleDesc"></result><collection property="permissions" column="rid" ofType="com.bootscoder.shopping_common.pojo.Permission"><id property="pid" column="pid"></id><result property="permissionName" column="permissionName"></result><result property="url" column="url"></result></collection></resultMap><select id="findById" parameterType="long" resultMap="roleMapper">SELECT * FROM boots_roleLEFT JOIN boots_role_permission on boots_role.rid = boots_role_permission.ridLEFT JOIN boots_permission on boots_role_permission.pid = boots_permission.pidWHERE boots_role.rid = #{rid}</select><delete id="deleteRoleAllPermission" parameterType="long">DELETE FROM boots_role_permission where rid = #{rid}</delete><delete id="deleteRoleAllAdmin" parameterType="long">DELETE FROM boots_admin_role where rid = #{rid}</delete><insert id="addPermissionToRole">INSERT INTO boots_role_permission values (#{rid},#{pid});</insert></mapper>

编写角色相关功能

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bootscoder.shopping_admin_service.mapper.PermissionMapper"><delete id="deletePermissionAllRole" parameterType="long">DELETE FROM boots_role_permission WHERE pid = #{pid}</delete>
</mapper>

修改角色权限时报错

image-20240416193015801

 @Overridepublic void updatePermissionToRole(Long rid, Long[] pids) {// 删除角色的所有权限roleMapper.deleteRoleAllPermission(rid);if (pids != null && pids.length > 0){// 给角色添加权限for (Long pid : pids) {roleMapper.addPermissionToRole(rid,pid);}	}}

删除所有权限 写成所有admin了

Spring Security 核心组件

在Spring Security 3.0中,spring-security-core jar的内容被剥离到最低限度。它不再包含与web相关的任何代码 - 应用程序安全性,LDAP或命名空间配置。我们将在这里看一下您在核心模块中可以找到的一些Java类型。它们代表了框架的构建块,因此如果您需要超越简单的命名空间配置,那么即使您实际上不需要直接与它们进行交互,您也必须了解它们是什么。

SecurityContextHolder,SecurityContext和Authentication Objects

最基本的对象是SecurityContextHolder。这是我们存储应用程序当前安全上下文的详细信息的地方,其中包括当前使用该应用程序的主体的详细信息。默认情况下,SecurityContextHolder使用ThreadLocal来存储这些详细信息,这意味着安全上下文始终可用于同一执行线程中的方法,即使安全上下文未作为参数显式传递那些方法。如果在处理当前委托人的请求之后小心地清除线程,以这种方式使用ThreadLocal是非常安全的。当然,Spring Security会自动为您解决这个问题,因此无需担心。

某些应用程序并不完全适合使用ThreadLocal,因为它们使用线程的特定方式。例如,Swing客户端可能希望Java虚拟机中的所有线程都使用相同的安全上下文。SecurityContextHolder可以在启动时配置策略,以指定您希望如何存储上下文。对于独立应用程序,您将使用SecurityContextHolder.MODE_GLOBAL策略。其他应用程序可能希望安全线程生成的线程也采用相同的安全标识。这是通过使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL来实现的。您可以通过两种方式从默认SecurityContextHolder.MODE_THREADLOCAL更改模式。第一个是设置系统属性,第二个是在SecurityContextHolder上调用静态方法。大多数应用程序不需要更改默认值,但如果这样做,请查看JavaDoc for SecurityContextHolder以了解更多信息。

获取有关当前用户的信息

SecurityContextHolder内,我们存储了当前与应用程序交互的主体的详细信息。Spring Security使用Authentication对象来表示此信息。您通常不需要自己创建Authentication对象,但用户查询Authentication对象是相当常见的。您可以使用以下代码块(从应用程序的任何位置)获取当前经过身份验证的用户的名称,例如:

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}

调用getContext()返回的对象是SecurityContext接口的实例。这是保存在线程本地存储中的对象。正如我们将在下面看到的,Spring Security中的大多数认证机制都返回UserDetails的实例作为主体。

UserDetailsService

上面代码片段中需要注意的另一个问题是,您可以从Authentication对象获取主体。校长只是Object。大多数情况下,这可以转换为UserDetails对象。UserDetails是Spring Security中的核心界面。它代表一个主体,但是以可扩展和特定于应用程序的方式。可以将UserDetails视为您自己的用户数据库与SecurityContextHolder内Spring Security所需的适配器之间的适配器。作为来自您自己的用户数据库的东西的表示,您经常会将UserDetails转换为您的应用程序提供的原始对象,因此您可以调用特定于业务的方法(如getEmail()getEmployeeNumber()和等等)。

到现在为止你可能想知道,所以我什么时候提供UserDetails对象?我怎么做?我以为你说这个东西是声明性的,我不需要编写任何Java代码 - 是什么给出的?简短的回答是有一个名为UserDetailsService的特殊界面。此接口上唯一的方法接受基于String的用户名参数并返回UserDetails

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

这是在Spring Security内为用户加载信息的最常用方法,只要需要有关用户的信息,您就会看到它在整个框架中使用。

上成功的认证,UserDetails被用来建立存储在SecurityContextHolder(关于这一点的Authentication对象下面)。好消息是我们提供了许多UserDetailsService实现,包括一个使用内存映射(InMemoryDaoImpl)和另一个使用JDBC(JdbcDaoImpl)的实现。但是,大多数用户倾向于自己编写,他们的实现通常只是位于代表其员工,客户或应用程序其他用户的现有数据访问对象(DAO)之上。记住使用上面的代码片段始终可以从SecurityContextHolder获得UserDetailsService返回的优点。

hello springSecurity!!!
UserDetailsService经常有些混乱。它纯粹是用户数据的DAO,除了将数据提供给框架内的其他组件之外,不执行任何其他功能。特别是,它不会对用户进行身份验证,这是由AuthenticationManager完成的。在许多情况下,如果您需要自定义身份验证过程,直接实现AuthenticationProvider会更有意义。
一个GrantedAuthority

除了校长之外,Authentication提供的另一个重要方法是getAuthorities()。此方法提供GrantedAuthority个对象的数组。毫不奇怪,GrantedAuthority是授予校长的权力。这些权力通常是“角色”,例如ROLE_ADMINISTRATORROLE_HR_SUPERVISOR。稍后将为web授权,方法授权和域对象授权配置这些角色。Spring Security的其他部分能够解释这些权威,并期望它们存在。GrantedAuthority对象通常由UserDetailsService加载。

通常GrantedAuthority对象是应用程序范围的权限。它们不是特定于给定的域对象。因此,你不可能有一个GrantedAuthority代表Employee对象编号54的权限,因为如果有数千个这样的权限,你很快就会耗尽内存(或者,至少,因为应用程序需要很长时间来验证用户身份)。当然,Spring Security专门用于处理这个常见要求,但您可以使用项目的域对象安全功能来实现此目的。

摘要

Spring Security的主要构建块是:

  • SecurityContextHolder,提供SecurityContext的访问权限。
  • SecurityContext,保存Authentication和可能的特定于请求的安全信息。
  • Authentication,以特定于Spring Security的方式代表校长。
  • GrantedAuthority,以反映授予主体的应用程序范围的权限。
  • UserDetails,提供从应用程序的DAO或其他安全数据源构建Authentication对象所需的信息。
  • UserDetailsService,在基于String的用户名(或证书ID等)中传递时创建UserDetails

既然您已经了解了这些重复使用的组件,那么让我们仔细看看身份验证过程。

Spring Security的整体原理

让我们考虑一个每个人都熟悉的标准身份验证方案。

  1. 提示用户使用用户名和密码登录。
  2. 系统(成功)验证用户名的密码是否正确。
  3. 获取该用户的上下文信息(他们的角色列表等)。
  4. 为用户建立安全上下文
  5. 用户继续进行,可能执行一些可能受访问控制机制保护的操作,该访问控制机制针对当前安全上下文信息检查操作所需的许可。

前三项构成了身份验证过程,因此我们将在Spring Security内查看这些过程是如何发生的。

  1. 获取用户名和密码并将其合并到UsernamePasswordAuthenticationToken的实例中(我们之前看到的Authentication接口的实例)。
  2. 令牌被传递给AuthenticationManager的实例以进行验证。
  3. AuthenticationManager在成功验证后返回完全填充的Authentication实例。
  4. 通过调用SecurityContextHolder.getContext().setAuthentication(…)建立安全上下文,传入返回的身份验证对象。

编写Security处理器

中文教程

接下来我们使用Spring Security编写管理员认证和授权功能。Spring Security在访问接口时进行认证和授权,所以Spring Security的相关代码编写在管理员API模块。

在springboot中使用Spring Security时,登录后会配置跳转页面。但boots商城是前后端分离项目,所有认证和授权的结果,只是返回json字符串让前端去处理。所以我们要创建认证成功处理器认证失败处理器未登录处理器权限不足处理器登出成功处理器处理不同的结果,Spring Security通过实现接口编写结果处理器。

主要解决两个问题:

  • 认证(Authentication)

解决你是谁的问题,具体表现为注册与登录

  • 授权(Authorization)

解决你能干什么的问题,你登录后有哪些权限。

引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
/***  登出成功处理器** @author bootsCoder* @date created on 2024/4/18*/
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)throws IOException {BaseResult result = new BaseResult(200, "注销成功", null);response.setContentType("text/json;charset=utf-8");response.getWriter().write(JSON.toJSONString(result));}
}

编写配置类

/*** Spring Security配置** @author bootsCoder* @date created on 2024/4/18*/
@Configuration
public class SecurityConfig {//@Beanprotected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {/***         自定义表单登录*/http.formLogin(form -> {form.usernameParameter("username") // 用户名项.passwordParameter("password") // 密码项.loginProcessingUrl("/admin/login") // 登录提交路径.successHandler(new LoginSuccessHandler()) // 登录成功处理器.failureHandler(new LoginFailHandler()); // 登录失败处理器});// 权限拦截配置http.authorizeHttpRequests(resp -> {resp.requestMatchers("/login", "/admin/login").permitAll(); // 登录请求不需要认证resp.anyRequest().authenticated();// 其余请求都需要认证});/***  退出登录配置*/http.logout(logout -> {logout.logoutUrl("/admin/logout") // 注销的路径.logoutSuccessHandler(new MyLogoutSuccessHandler()) // 登出成功处理器.clearAuthentication(true) // 清除认证数据.invalidateHttpSession(true);// 清除session});// 异常处理http.exceptionHandling(exception -> {exception.authenticationEntryPoint(new MyAuthenticationEntryPoint())// 未登录处理器.accessDeniedHandler(new MyAccessDeniedHandler()); // 权限不足处理器});// 跨域访问http.cors();// 关闭csrf防护http.csrf(csrf ->{csrf.disable();});return http.build();}/***     加密工具*/@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}
image-20240418145958970

编写认证授权相关的服务方法

  <select id="findAllPermission" resultType="com.bootscoder.shopping_common.pojo.Permission" parameterType="string">SELECTDISTINCT boots_permission.*FROMboots_adminLEFT JOIN boots_admin_roleON boots_admin.aid = boots_admin_role.aidLEFT JOIN boots_roleON boots_admin_role.rid = boots_role.ridLEFT JOIN boots_role_permissionON boots_role.rid = boots_role_permission.ridLEFT JOIN boots_permissionON boots_role_permission.pid = boots_permission.pidWHERE boots_admin.username = #{username}</select>

编写认证授权逻辑

/*** 认证授权逻辑** @author bootsCoder* @date created on 2024/4/18*/
@Service
public class MyUserDetailService implements UserDetailsService {@DubboReferenceprivate AdminService adminService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 1.认证Admin admin = adminService.findByAdminName(username);if(admin == null){throw new UsernameNotFoundException("用户不存在");}// 2.授权List<Permission> permissions = adminService.findAllPermission(username);List<GrantedAuthority> grantedAuthorities = new ArrayList<>();if (permissions.get(0) != null){for (Permission permission : permissions) {grantedAuthorities.add(new SimpleGrantedAuthority(permission.getUrl()));}}// 3.封装为UserDetails对象UserDetails userDetails = User.withUsername(admin.getUsername()).password(admin.getPassword()).authorities(grantedAuthorities).build();// 4.返回封装好的UserDetails对象return userDetails;}
}

修改新增修改管理员方法-- 添加加密

 @Overridepublic void update(Admin admin) {// 如果前端传来空密码,则密码还是原来的密码if(!StringUtils.hasText(admin.getPassword())){// 查询原来的密码String password = adminMapper.selectById(admin.getAid()).getPassword();admin.setPassword(password);}adminMapper.updateById(admin);}@PutMapping("/update")public BaseResult update(@RequestBody Admin admin) {String password = admin.getPassword();// 密码不为空加密if (StringUtils.hasText(password)){password = encoder.encode(password);admin.setPassword(password);}adminService.update(admin);return BaseResult.ok();}

权限管理_获取登录管理员名&接口鉴权配置

 /*** 分页查询角色* @param page 页码* @param size 每页条数* @return 查询结果*/@GetMapping("/search")@PreAuthorize("hasAnyAuthority('/role/search')")public BaseResult<Page<Role>> search(int page, int size){Page<Role> rolePage = roleService.search(page, size);return BaseResult.ok(rolePage);}

image-20240418154747346

mybatis 封装的时候 为空时判list长度 1

 // 2.授权List<Permission> permissions = adminService.findAllPermission(username);List<GrantedAuthority> grantedAuthorities = new ArrayList<>();if (permissions.get(0) != null){for (Permission permission : permissions) {grantedAuthorities.add(new SimpleGrantedAuthority(permission.getUrl()));}}

image-20240418155141020

测试认证功能成功


http://www.mrgr.cn/p/06688645

相关文章

栈1: 栈的顺序存储

栈: 顺序存储栈是一种先进后出(First In Last Out,FILO)的数据结构 如果你将两个元素压入栈,先加入的元素将在后加入的元素之后出栈栈顶元素值为null(未满时)定义栈的数据结构 #define MAX_SIZE 1024 //利用数组模拟栈的顺序存储 typedef struct sqStack{void *data[MAX_SIZE]…

C#医学实验室/检验信息管理系统(LIS系统)源码

目录 检验系统的总体目标 LIS主要包括以下功能&#xff1a; LIS是集&#xff1a;申请、采样、核收、计费、检验、审核、发布、质控、耗材控制等检验科工作为一体的信息管理系统。LIS系统不仅是自动接收检验数据&#xff0c;打印检验报告&#xff0c;系统保存检验信息的工具&a…

云原生之在kubernetes集群下部署mysql应用

一、Mysql介绍数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。MySQL是一种开源的关系型数据库管理系统,可将数据保存在不同的表中,而不是将所有数据放在一个大的仓库内,从而加快了访问速度并提高了灵活性。MySQL 使用了标准的 SQL 语言形式。支持大型的数据…

Trino418版本动态加载catalog不需要重启集群修改思路及实现2

原来没事的时候改了一个这样的功能,当时也没有仔细研究,后来也没继续弄。详细可以参考 https://www.cnblogs.com/liuzx8888/p/17635913.html 当时有1个问题:新增数据源需要每一个节点都去调取API注册,这样非常麻烦,最近闲下来又研究了一下,在原先的基础上做了一些改造。 …

小程序生态是更灵活构建超级App的方式

第三方中立应用市场作为一种新兴模式,打破了现有应用市场的垄断格局,为开发者和用户带来了新的选择和机遇。它拥有连接超级App流量及用户的独特优势,能够聚合流量、提升用户体验、创新模式、保障数据安全,并有望成为应用市场发展的新趋势。互联网从1.0发展至今,已经经历了…

游戏服务器DDOS克星-抗D盾(游戏盾)

随着网络游戏市场的不断扩大和发展&#xff0c;游戏服务器遭受DDOS攻击的频率也在逐年增加。DDOS攻击的主要目的是使游戏服务器瘫痪&#xff0c;使得游戏无法正常进行&#xff0c;导致游戏运营商巨额损失。鉴于此&#xff0c;针对游戏服务器的防DDOS攻击技术德迅云安全自主研发…

个人博客系统项目(SpringBoot+Linux部署上线)

在学完SpringBoot框架、MyBatis后&#xff0c;直接开始做第一个项目&#xff1a;博客系统 首先&#xff0c;该博客系统包含核心功能有&#xff1a; 一、登录、注册、退出登录功能。 二、没有登陆前可以查看博客首页以及博客展示的分页处理&#xff0c;以及点击查看博客可以…

代码安全有门道:研发团队的数据防护手册

在快速发展的科技行业&#xff0c;研发团队掌握着企业的心脏——代码。源代码不仅承载着创新思想&#xff0c;也代表了无数的研发投入和商业机会。然而&#xff0c;2018年GitLab的一次安全漏洞导致数千个私有代码仓库被删除&#xff0c;这起事件警示我们&#xff0c;没有严格的…

Java面试:MySQL面试题汇总

1.说一下 MySQL 执行一条查询语句的内部执行过程&#xff1f; 答&#xff1a;MySQL 执行一条查询的流程如下&#xff1a; 客户端先通过连接器连接到 MySQL 服务器&#xff1b;连接器权限验证通过之后&#xff0c;先查询是否有查询缓存&#xff0c;如果有缓存&#xff08;之前…

数据治理

数据治理对于企业来说至关重要。它可以帮助企业清晰地了解自己的数据资源、数据流和数据质量。通过有效的数据治理,企业能够更好地管理和控制数据,最大化数据的价值,并在决策过程中减少错误和风险。数据治理的步骤及原则数据收集和整合数据治理的第一步是收集和整合数据。这…

ubuntu如何截图? ubuntu中截屏的三种方法

文章目录 1.ubuntu主要用途2.ubuntu如何截图&#xff1f;2.1 方法一&#xff1a;键盘按键快捷键截屏 2.2 方法二&#xff1a;系统自带软件2.3 方法三&#xff1a;第三方软件 Reference 1.ubuntu主要用途 1、桌面操作系统&#xff1a;Ubuntu可用作个人电脑或笔记本电脑的操作系…

Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机

Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机 文章目录 Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机1.安装virtualbox2.下载Window.iso文件并载入3.问题解决3.1 Kernel driver not installed (rc-1908)3.2 VT-x is disabled in the BIOS for all CPU modes 4.安装Wi…

简述Linux磁盘IO

1、什么是磁盘在讲解磁盘IO前,先简单说下什么是磁盘。磁盘是可以持久化存储的设备,根据存储介质的不同,常见磁盘可以分为两类:机械磁盘和固态磁盘。 1.1 机械磁盘第一类,机械磁盘,也称为硬盘驱动器(Hard Disk Driver),通常缩写为 HDD。机械磁盘主要由盘片和读写磁头组…

互连芯片浪潮席卷AI服务器:突破瓶颈,再创辉煌

改变AI服务器&#xff1a;互连芯片技术创新和突破 AI服务器崛起&#xff0c;引领未来创新根据TrendForce数据&#xff0c;AI服务器出货量达130,000台&#xff0c;占服务器总出货量的1%。主要制造商推出生成式AI产品&#xff0c;推动订单激增。ChatGPT等应用的需求持续增长&…

【MySQL】20. 使用C语言链接

mysql connect mysql的基础&#xff0c;我们之前已经学过&#xff0c;后面我们只关心使用 要使用C语言连接mysql&#xff0c;需要使用mysql官网提供的库&#xff0c;大家可以去官网下载 我们使用C接口库来进行连接 要正确使用&#xff0c;我们需要做一些准备工作&#xff1a; …

【springCloud】版本学习

Spring Cloud介绍 官网地址&#xff1a;https://spring.io/projects/spring-cloud Spring Cloud 是一个基于 Spring Boot 的微服务架构解决方案&#xff0c;它提供了一系列工具和模式来帮助开发者构建分布式系统。Spring Cloud 的组件和模式包括配置管理、服务发现、断路器、…

P8968

太牛了。太 nb 了。 不会博弈,不会推导,盲猜全部是同种电荷,此时神明的决策固定且易于刻画,对着样例模拟一下发现对了,写一发过了 easy ver,于是不管正确性直接来想 hard ver。 考虑向上跳的过程大致操作为 \(x\gets x+\min(x,a_i)\),直觉上不存在好的维护方法。 注意到…

ELK日志收集和备份填坑实战 (滞后8个小时等时区问题)

ES的备份&#xff1a;ES快照备份 根据时间&#xff0c;每天零点在Linux机器crontab来调用api接口实现快照备份&#xff0c;通过快照备份&#xff0c;可以定准恢复到某一天的日志。 现象&#xff1a;&#xff08;坑&#xff1a;但是恢复某一天日志&#xff0c;发现会少8小时的日…

初学python记录:力扣2007. 从双倍数组中还原原数组

题目&#xff1a; 一个整数数组 original 可以转变成一个 双倍 数组 changed &#xff0c;转变方式为将 original 中每个元素 值乘以 2 加入数组中&#xff0c;然后将所有元素 随机打乱 。 给你一个数组 changed &#xff0c;如果 change 是 双倍 数组&#xff0c;那么请你返…

shell系统函数和流程控制

系统函数: 1、简单示例:点击查看代码 #!/bin/bash filename="$1"_log_$(datename +%S) echo $filenamebasename:基本语法: basename [string/pathname] [suffix] (功能描述:basename命令会删掉所有的前缀包括最后一个(/)字符,然后将左右字符显示出来。 basename…