1.SpringSecurity -快速入门、加密、基础授权

SpringSecurity简介

文章目录

  • SpringSecurity简介
  • 一、基本概念
    • 1.1 认证(Authentication)方式
    • 1.2 会话(Session)介绍
    • 1.3 授权(Authorization)介绍
    • 1.4 RBAC
  • 二、SpringSecurity入门
    • 2.1 快速入门
      • 2.1.1 Maven坐标
      • 2.1.2 接口
      • 2.1.3 源码
    • 2.2 配置文件配置用户名和密码
    • 2.3 基于内存的多用户管理
  • 三、加密
    • 3.1 密码加密学习
    • 3.2 BCryptPasswordEncoder
  • 四、权限信息

一、基本概念

1.1 认证(Authentication)方式

系统为什么要认证

认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源

什么是认证(登录)

用户认证就是判断一个用户的身份是否合法的过程

常见的用户身份认证方式

  • 用户名密码登录
  • 二维码登录
  • 手机短信登录
  • 指纹认证
  • 人脸识别

1.2 会话(Session)介绍

下面这个文章中有对session的理解:基于Session实现短信登录_c# 登录session怎么使用_我爱布朗熊的博客-CSDN博客

过滤器与拦截器 - 登录校验与登录认证(JWT令牌技术)_jwt过滤器_我爱布朗熊的博客-CSDN博客

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。

会话就是系统为了保持当前用户的登录状态所提供的机制

常见的有基于session方式、基于token方式

  • 基于session的认证方式

    它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的sesssion_id 存放到 cookie 中,这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id也就无效了。

有一些用户在使用浏览器的时候会禁用Cookie,这会导致发一次请求,用户登录一次

  • 基于token的认证方式

    它的交互流程是,用户认证成功后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。可以使用Redis 存储用户信息(分布式中共享session)。

    基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持cookie;基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式。如今移动互联网时代更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。

1.3 授权(Authorization)介绍

为什么要授权(控制资源被访问)?

因为不同的用户可以访问的资源不一样

什么是授权(给用户颁发权限)?

授权是用户认证通过后,根据用户的权限来控制用户访问资源的过程

拥有资源的访问权限则正常访问,没有权限则拒绝访问

1.4 RBAC

RBAC(Role-Based Access Control) 基于角色的访问控制

image-20230925222010168

用户,角色,权限 本质:就是把权限打包给角色(角色拥有一组权限),又将角色分配给用户(用户拥有多个角色)。

最少包括五张表 (用户表、角色表、用户角色表、权限表、角色权限表)

二、SpringSecurity入门

声明式(注解)的安全访问控制解决方案的安全框架

提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作

2.1 快速入门

2.1.1 Maven坐标

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.4.2</version>
</dependency>

2.1.2 接口

@RestController
@RequestMapping("/hello")
public class HelloController {@GetMapping("/hello")private String hello(){return "hello";}}

访问上面的接口就会出现下面的页面(登录)

image-20231007105125017

默认的用户名是User,密码是在控制台上的UUID

image-20231007105319945

登录上后便可以访问接口。

之后不会使用这种方式

我们也可以退出,访问IP:端口号/logout

image-20231007105829342

2.1.3 源码

为什么默认的用户名是user并且密码是一串UUID

如下代码所示

image-20231007111234007

2.2 配置文件配置用户名和密码

在配置文件中配置如下信息

spring:security:user:name: adminpassword: 123456

此时我们再使用默认的用户就不行了,而且控制台也不会输出UUID形式的密码了

image-20231007110802830


Spring Security配置文件中默认配置用户是单一的用户,大部分系统都有多个用户,多个用户如何配置

可以使用基于内存的多用户管理

2.3 基于内存的多用户管理

2.2 中配置的用户名和密码只能配置一个,但是我们的系统有许多的用户名和密码。

/*** 自定义类实现用户详情服务接口**   系统中默认是有这个UserDetailsService的,也就是默认的用户名(user)和默认密码(控制台生成的)*   如果在yaml文件中配置了用户名和密码,那在系统中的就是yaml文件中的信息** 我们自定义了之后,就会把系统中的UserDetailsService覆盖掉*/
@Configuration
public class MySecurityUserConfig  {/*** 根据用户名把用户的详情从数据库中获取出来,封装成用户细节信息UserDetailsService(包括用户名、密码、用户所拥有的权限)** UserDetails存储的是用户的用户名、密码、去权限信息*/@Beanpublic UserDetailsService userDetailsService() {
//      用户细节信息,创建两个用户
//      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainerUserDetails user1 =User.builder().username("zhangjingqi1").password("123456").roles("student").build();UserDetails user2 = User.builder().username("zhangjingqi2").password("123456789").roles("teacher").build();//      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsServiceInMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();userDetailsManager.createUser(user1);userDetailsManager.createUser(user2);return  userDetailsManager;}
}   

上面的程序启动会报错,原因

SpringSecurity强制要使用密码加密,当然我们也可以不加密,但是官方要求是不管你是否加密,都必须配置一个密码编码(加密)器

/*** 自定义用户必须配置密码加密器。* NoOpPasswordEncoder.getInstance() 此实例表示不加密*/
@Bean
public PasswordEncoder passwordEncoder(){return NoOpPasswordEncoder.getInstance();
}

此时用户名和密码就是user1与user2中配置的用户名和密码(此时配置文件中的用户名和密码会失效)

image-20231014192803769

image-20231014192744528



UserDetails类如下所示:

image-20231014190836999

三、加密

3.1 密码加密学习

  • 密码为什么要加密

CSDN网站六百万用户信息外泄-月光博客 (williamlong.info)

在加解密时一定要注意,我们要使用明文能加密成密文但是密文解密不成明文的加密算法

如果密文能解密,那我们加密的效果其实不算太好,黑客照样还是可以破译

image-20231014211903859

  • 加密的方式有哪些涉及到密码加密问题

    密码加密一般使用散列函数,又称散列算法,哈希函数,这些函数都是单向函数(从明文到密码,反之不行)

    常见的散列算法有MD5和SHA

    SpringSecurity提供了多种密码加密方案,基本上都实现了PasswordEncode接口官方推荐使用BCryptPasswordEncode

    image-20231014213450153

image-20231014213514723

  • NoOpPasswordEncoder类已经过期了,而且还没有加密,怎么解决

  • 以学生身份登录,发现不但可以访问学生的页面,还可以访问教师的页面和管理员的页面,如何解决

    权限问题,后面解决

  • 如果要动态的创建用户,或者修改密码等(不是把用户名和密码写死到代码中),怎么办

热疹信息存储到数据库中

3.2 BCryptPasswordEncoder

        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();String encode1 = passwordEncoder.encode("123456");String encode2 = passwordEncoder.encode("123456");String encode3 = passwordEncoder.encode("123456");System.out.println(encode1);//$2a$10$hkaTFSnsEBYcZxXMrDpMQu.IiPM5ZAIQ63Vvkq01.oxxv0yVRmKlySystem.out.println(encode2);//$2a$10$nuPqwjhW0e/RZ.h3L1gZx.KanwUNQd4GEB2YoeB/LeVOhavcoBS7OSystem.out.println(encode3);//$2a$10$SPHV9tuI6JhgOwDO2hMR4eq43E5BGmYJDQJ5GltIuK7WSQqi1sHzm//      参数1:原文   参数2:密文boolean result1 = passwordEncoder.matches("123456", encode1);boolean result2 = passwordEncoder.matches("123456", encode2);System.out.println(result1);//trueSystem.out.println(result2);//true

补充断言的知识

如果result1的结果是true的话,运行时的标记就是”√“,反之则是“×”

assertTrue(result1);//期望result1为true
assertFalse(result2);//期望result2为true

以下就是错误的情况

image-20231014220215113

我们可以将PasswordEncoder放入到Bean工厂中

/*** 配置密码加密器* NoOpPasswordEncoder.getInstance() 此实例表示不加密* BCryptPasswordEncoder() 会加密*/
@Bean
public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();
}

修改我们之前的程序

    @Beanpublic UserDetailsService userDetailsService() {
//      用户细节信息,创建两个用户
//      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainerUserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456")).roles("student").build();UserDetails user2 = User.builder().username("zhangjingqi-2").password(passwordEncoder().encode("123456")).roles("teacher").build();//      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsServiceInMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();userDetailsManager.createUser(user1);userDetailsManager.createUser(user2);return  userDetailsManager;}

四、权限信息

4.1 获取登录用户信息

关于已经验证实体的详情被存储到安全性上下文中(SpringContext)

image-20231014222351220

如果用户名和密码正确,说明认证成功

此时会把认证信息放到Authentication中,再把Authentication放到SecurityContext中

然后可以通过安全上下文持有器SecurityContextHolder获取安全上下文

/*** 获取用户登录信息的方式*/
@RestController
@Slf4j
public class CurrentLoginUserController {/*** import org.springframework.security.core.Authentication;* 一旦登录成功,访问下面的请求就可以得到authentication** Authentication 继承 Principal**/@GetMapping("/getLoginUser1")public Authentication getLoginUser1(Authentication authentication) {return authentication;}/***import java.security.Principal;* 一旦登录成功,访问下面的请求就可以得到principal*/@GetMapping("/getLoginUser2")public Principal getLoginUser2(Principal principal) {return principal;}/*** 一旦我们登陆成功,框架就会把我们的信息放到安全性上文中SpringContext* 所以我们可以通过安全性上文SpringContext获取用户信息*/@GetMapping("/getLoginUser3")public Principal getLoginUser3() {
//      通过安全上下文持有器获取安全上下文return SecurityContextHolder.getContext().getAuthentication();}}

访问:localhost:8080/getLoginUser1

“name”用户名

“credentials”凭据,其实就是密码,这里是null的原因就是直接给展示密码太不安全了,所以显示为null

“authorities”权限信息,授权,权限

“principal”中的内容就是代码UserDetails中定义的内容

image-20231014224745740

"accountNonExpired"账户是否未过期,true表示未过期

"accountNonLocked"账户是否未锁定,true表示未锁定

"credentialsNonExpired"凭证是否未过期,true表示未过期,这里的凭证一般是指密码
**“enabled”**账户是否可用,true表示可用

只有当"accountNonExpired"、“accountNonLocked”、“credentialsNonExpired”、"enabled"都为true时,账户才能使用

image-20231014223719223

4.2 配置用户权限

如下图所示,便是给用户配置权限

image-20231015151149649

其中roles可以配置多个角色,其有一个可变数组,这样来说一个用户可以配置多个角色

UserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456")).roles("student","manager").build();

image-20231015151234272

下面来配置一下用户的权限

    @Beanpublic UserDetailsService userDetailsService() {
//      用户细节信息,创建两个用户
//      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainerUserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456"))
//               配置用户角色.roles("student", "manager") //角色到系统中会变成权限的,比如这里会变成ROLE_student,ROLE_manager
//               配置用户权限. student:delete权限处理学生的删除,student:add权限处理学生的添加.authorities("student:delete","student:add").build();UserDetails user2 = User.builder().username("zhangjingqi-2").password(passwordEncoder().encode("123456"))
//              配置权限.authorities("teacher:delete", "teacher:add")
//              配置角色.roles("teacher").build();//      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsServiceInMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();userDetailsManager.createUser(user1);userDetailsManager.createUser(user2);return userDetailsManager;}

登录zhangjingqi-1账号,访问localhost:8080/getLoginUser3

我们发现,JSON串中“authorities”的内容是中配置的”authorities“,而没有将“roles”变成权限

image-20231015152408310

之后再登录zhangjingqi-2账号访问localhost:8080/getLoginUser3,我们发现下面的JSON串中”authorities“是在代码中配置的“roles”角色信息转换成的权限

image-20231015152855592

所以配置用户权限我们得出一个结论:

  • 在代码中配置“authorities“与“roles”时,谁再后面谁执行,后者会覆盖前者;

  • 配置的”roles“角色信息,在前面添加一个“ROLE_”前缀就会变成权限信息

  • 系统不会给配置的”authorities“权限信息添加任何前缀

4.3 针对URL授权

此控制级别只在Controller层

虽然我们实现了认证功能,但是受保护的资源是默认的,默认所有认证(登录)用户均可以访问所有资源,不能根据实际情况进行角色管理

实现授权功能,需重新WebSecurityConfigurerAdapter中的一个configure方法

虽然之前我们配置了用户角色和用户权限,但是用户登录上之后依然可以随便访问,比如说“student”角色可以访问“teacher”角色对应的功能。

4.3.1 拒绝任何请求

如下代码所示:表示拒绝任何http请求

虽然可以使用zhangjingqi-1或zhangjingqi-2认证成功登录,但是Controller不让访问,并且包括springSecurity框架中的login也会被屏蔽掉

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/*** 重写 configure(HttpSecurity http)方法*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权http请求.anyRequest()//任何请求.denyAll();//拒绝}

访问http://localhost:8080/login如下所示

image-20231015155702659

4.3.2 允许登录表单

为了可以访问http://localhost:8080/login,我们可以使用下面的一个配置

    /*** 重写 configure(HttpSecurity http)方法*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权http请求.anyRequest()//任何请求.denyAll();//拒绝http.formLogin().permitAll();//允许表单登录}

此时就可以看到下面的登录界面了,但是如果访问其他请求,就会被拒绝

image-20231015160916199

4.3.3 允许任何请求

    /*** 重写 configure(HttpSecurity http)方法*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权http请求.anyRequest()//任何请求.permitAll();//允许任何请求http.formLogin().permitAll();//允许表单登录}

4.3.4 匹配请求

zhangjingqi-1对应的权限:student:delete、student:add

zhangjingqi-2对应的权限:ROLE_teacher

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/*** 重写 configure(HttpSecurity http)方法*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权http请求.mvcMatchers("/student/**")// 匹配/student开头的请求.hasAnyAuthority("student:add")// 拥有student:add权限的用户可以访问上面的url.mvcMatchers("/teacher/**") // 匹配/teacher/**开头的请求.hasAnyAuthority("ROLE_teacher")//拥有ROLE_teacher权限的用户可以访问/teacher/**开头的url.anyRequest()// 任何请求.authenticated()//需要验证。注意:没有配置的url,只要登录成功就可以访问;http.formLogin().permitAll();//允许表单登录}
}

使用zhangjingqi-1访问一下localhost:8080/student/hello

image-20231015162519777

使用zhangjingqi-1访问一下localhost:8080/hello/hello

image-20231015162537580

使用zhangjingqi-1访问一下localhost:8080/teacher/hello

image-20231015162553881

使用zhangjingqi-2访问一下http://localhost:8080/student/hello

image-20231015162750496

使用zhangjingqi-2访问一下localhost:8080/hello/hello

image-20231015162537580

使用zhangjingqi-2访问一下localhost:8080/teacher/hello

image-20231015162818021

4.3.5 总结

  • 匹配请求的三种方式
.mvcMatchers("/student/**")
.regexMatchers("/student/**")
.anyMatchers("/student/**")
  • 判断权限的五种方式

推荐第一种

.hasAuthority("ROLE_teacher") //是否有单个权限,参数只能写一个权限
.hasAnyAuthority("ROLE_teacher","student:add")//是否有其中的任意一个权限
.access( "hasAuthority('student:query') or  hasAuthority('student:add')")
.hasRole("student") // 是否有单个角色
.hasAnyRole("student") //是否有其中的某个角色
  • 先写匹配路径,再写对应的权限

4.4 针对方法进行授权

下面 通过更灵活的配置方法安全,我们先通过@EnableGlobalMethodSecurity开启基于注解的安全配置

4.4.1 抽象类

public interface TeacherService {String add();String update();String delete();String query();
}

4.4.2 实现类

@Slf4j
@Service
public class TeacherServiceImpl implements TeacherService {//预授权注解,此处采用表达式的形式。//如果有teacher:add权限,才会执行下面这个方法;反之不会访问@PreAuthorize("hasAuthority('teacher:add')")@Overridepublic String add() {log.info("添加教师成功");return "添加教师成功";}//只要有teacher:update或teacher:add权限其中之一,便可以执行下面的方法@PreAuthorize("hasAnyAuthority('teacher:update','teacher:add')")@Overridepublic String update() {log.info("修改教师成功");return "修改教师成功";}@PreAuthorize("hasAuthority('teacher:delete')")@Overridepublic String delete() {log.info("删除教师成功");return "删除教师成功";}@PreAuthorize("hasAuthority('teacher:query')")@Overridepublic String query() {log.info("查询教师成功");return "查询教师成功";}
}

4.4.3 teacher的Controller

@RestController
@RequestMapping("/teacher")
public class TeacherController {@Resourceprivate TeacherService teacherService;@GetMapping("/query")public String queryInfo() {return teacherService.query();}@GetMapping("/add")public String addInfo() {return teacherService.add();}@GetMapping("/update")public String updateInfo() {return teacherService.update();}@GetMapping("/delete")public String deleteInfo() {return teacherService.delete();}
}

4.4.4 用户详情服务接口配置类

@Configuration
public class MySecurityUserConfig {/*** 根据用户名把用户的详情从数据库中获取出来,封装成用户细节信息UserDetails(包括用户名、密码、用户所拥有的权限)* <p>* UserDetails存储的是用户的用户名、密码、去权限信息*/@Beanpublic UserDetailsService userDetailsService() {
//      用户细节信息,创建两个用户
//      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainerUserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456"))
//               配置用户角色.roles("student") //角色到系统中会变成权限的,比如这里会变成ROLE_student,ROLE_manager.build();UserDetails user2 = User.builder().username("zhangjingqi-2").password(passwordEncoder().encode("123456"))
//              配置权限.authorities("teacher:query").build();UserDetails user3 = User.builder().username("admin").password(passwordEncoder().encode("123456"))
//              配置权限.authorities("teacher:query","teacher:add","teacher:update","teacher:delete").build();//      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsServiceInMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();userDetailsManager.createUser(user1);userDetailsManager.createUser(user2);userDetailsManager.createUser(user3);return userDetailsManager;}/*** 配置密码加密器* NoOpPasswordEncoder.getInstance() 此实例表示不加密* BCryptPasswordEncoder() 会加密*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

4.4.5 安全配置

WebSecurityConfig这个地方其实是URL的权限配置

预授权:在访问方法之前判断有无权限(使用量最大)

后授权:访问完方法后再判断有无权限

//@Configuration
//开启全局方法安全。 prePostEnabled = true 表示预授权和后授权开启
//此注解中包含@Configuration注解,所以不用重复标识
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权http请求.anyRequest() //任何请求.authenticated();//都需要认证http.formLogin().permitAll();//允许表单登录//      或者下面这种形式
//        http.authorizeRequests()//授权http请求
//                .anyRequest() //任何请求
//                .authenticated()//都需要认证
//                .and()
//                .formLogin().permitAll();}
}

4.4.6 测试

用户admin,访问localhost:8080/teacher/query

image-20231016213447361

用户admin,访问localhost:8080/teacher/add

image-20231016213506529

用户zhangjingqi-2,访问localhost:8080/teacher/query

image-20231016213447361

用户zhangjingqi-2,访问localhost:8080/teacher/add

image-20231016213634402

用户zhangjingqi-1,访问localhost:8080/teacher/query

image-20231016213716614

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

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

相关文章

[netty-websocket-boot-starter] 轻量、高性能的WebSocket框架

简介 这是一个轻量级、高性能的基于 Netty 的 WebSocket 框架&#xff0c;提升你的 WebSocket 开发体验&#xff0c;为 Spring Boot 带来全新的 WebSocket 功能。 该项目使你可以轻松集成 WebSocket 到你的 Spring Boot 项目中&#xff0c;提供了 Tomcat WebSocket 的简单性&a…

[QCM6125][Android13] 默认允许使用usb权限

文章目录 开发平台基本信息问题描述解决方法 开发平台基本信息 芯片: QCM6125 版本: Android 13 kernel: msm-4.14 问题描述 设备有usb打印机&#xff0c;调用UsbManager进行打印时&#xff0c;会弹框请求使用usb权限&#xff1b;客户要求能够自动授权usb权限&#xff0c;应…

Kotlin中的算数运算符

在Kotlin中&#xff0c;我们可以使用各种算术运算符来进行数值计算和操作。下面对这些运算符进行详细描述&#xff0c;并提供示例代码。 正号&#xff08;正数&#xff09;和负号&#xff08;负数&#xff09;&#xff1a; 正号用于表示一个正数&#xff0c;不对数值进行任何…

微信小程序前端生成动态海报图

//页面显示<canvas id"myCanvas" type"2d" style" width: 700rpx; height: 600rpx;" />onShareShow(e){var that this;let user_id wx.getStorageSync(user_id);let sharePicUrl wx.getStorageSync(sharePicUrl);if(app.isBlank(user_i…

Linux性能优化--使用性能工具发现问题

9.0 概述 本章主要介绍综合运用之前提出的性能工具来缩小性能问题产生原因的范围。阅读本章后&#xff0c;你将能够&#xff1a; 启动行为异常的系统&#xff0c;使用Linux性能工具追踪行为异常的内核函数或应用程序。启动行为异常的应用程序&#xff0c;使用Linux性能工具追…

【AI】了解人工智能、机器学习、神经网络、深度学习

深度学习、神经网络的原理是什么&#xff1f; 深度学习和神经网络都是基于对人脑神经系统的模拟。下面将分别解释深度学习和神经网络的原理。深度学习的原理&#xff1a;深度学习是一种特殊的机器学习&#xff0c;其模型结构更为复杂&#xff0c;通常包括很多隐藏层。它依赖于神…

一文全面了解:react-antd-admin 如何封装 axios

在React中封装Axios并添加请求拦截、响应拦截和错误处理是一个常见的需求,可以通过创建一个包装的Axios实例来实现。以下是一个简单的示例,展示如何在React中封装Axios: 首先,确保你已经安装了Axios,如果没有安装,可以使用以下命令进行安装: npm install axios然后,你…

C#中lock 和 ReaderWriterLock 的使用总结

线程锁是多线程并发共享数据&#xff0c;保证一致性的工具。多线程可以同时运行多个任务但是当多个线程同时访问共享数据时&#xff0c;可能导致数据不同步。当有多个线程访问同一对象的加锁方法或代码块时&#xff0c;同一时间只有一个线程在执行&#xff0c;其余线程必须要等…

新加坡服务器托管

新加坡是一个小而繁荣的国家&#xff0c;是东南亚唯一一个发达国家。它地理位置好&#xff0c;毗邻马来西亚和印度尼西亚&#xff0c;新加坡是一个拥有先进科技和强大经济的国家&#xff0c;主要以制造业、金融、旅游和航运为主&#xff0c;拥有先进的经济和现代化的基础设施&a…

C++进阶篇1---继承

一、继承的概念和定义 1.1概念 继承机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称为派生类。继承呈现了面向对象程序设计的层次结构&#xff…

AFL模糊测试+GCOV覆盖率分析

安全之安全(security)博客目录导读 覆盖率分析汇总 目录 一、代码示例 二、afl-cov工具下载 三、编译带覆盖率的版本并启动afl-cov 四、AFL编译插桩并运行afl-fuzz 五、结果查看 AFL相关详见AFL安全漏洞挖掘 GCOV相关详见GCOV覆盖率分析 现将两者结合&#xff0c;即进…

添加Mybatis框架支持

配置环境 1.老项目 在pom.xml中使用generate ->edit starts->添加下面俩 2.新项目 然后运行发现会有报错 2.1这是因为没有配置数据库连接信息 spring:datasource:url: jdbc:mysql://localhost:3306/java2023?characterEncodingutf8&useSSLfalse # MySQL数…

PDF编辑阅读:Acrobat Pro DC 2021中文稳定版

Acrobat Pro DC 2021是一款专业的PDF编辑和阅读软件。它可以创建、编辑、组合、签署和分享PDF文件&#xff0c;提供了许多强大的功能&#xff0c;如PDF文件转换、OCR识别、PDF文件合并、加密和解密等等。Acrobat Pro DC 2021的界面简单直观&#xff0c;易于使用&#xff0c;而且…

四.镜头知识之放大倍率

四.镜头知识之放大倍率 文章目录 四.镜头知识之放大倍率4.0 前言4.1 镜头的光学放大倍率的计算方法4.2 显示器的电子放大倍率4.2.1 智能硬件产品的显示放大倍率计算案例4.3 系统放大倍率4.4 智能硬件产品的系统放大倍率计算案例4.4 智能硬件产品的系统放大倍率计算案例4.0 前言…

为什么学校互联网专业教的只是出社会都没用?

今日话题&#xff0c;为什么很多学生都觉得认真学习了学校课程&#xff0c;但是出社会企业发现一点用都没有&#xff1f;解决方法放在了后方&#xff0c;免费领取。首先&#xff0c;计算机技术的迅猛发展导致学校教材和课程更新滞后&#xff0c;可能学到的知识已是老旧。嵌入式…

JNDI-Injection-Exploit工具安装

从github上下载安装 git clone https://github.com/welk1n/JNDI-Injection-Exploit.git 打开 cd JNDI-Injection-Exploit 编译安装&#xff0c;Maven入门百科_maven中quickstart是什么意思-CSDN博客 mvn clean package -DskipTests 因为提示mvn错误&#xff0c;解决下…

leetcode-200. 岛屿数量

1. 题目 leetcode题目链接 2. 解答 思路&#xff1a; 需要循环遍历每个节点&#xff1b;找到陆地&#xff0c;基于陆地开始遍历陆地的上下左右&#xff1b;数组dirm dirn就可以表示某个区域的上下左右&#xff1b;标记遍历过的节点&#xff1b;设计循环的退出条件&#xf…

Mybatis Available parameters are [0, 1, param1, param2]解决方法

Mybatis Available parameters are [0, 1, param1, param2]解决方法 原因 这与Mybatis的参数匹配机制有关&#xff0c;当传递多个参数的时候&#xff0c;映射机制并不清楚如何匹配到正确的参数 方法一&#xff1a;使用Param参数 方法二&#xff1a;使用Map传参数

图论-最短路径算法-弗洛伊德算法与迪杰斯特拉算法

弗洛伊德算法&#xff1a; 弗洛伊德算法本质是动态规划&#xff0c;通过添加点进如可选择的点组成的集合的同时更新所有点之间的距离&#xff0c;从而得到每两个点之间的最短距离。 初始化&#xff1a; 创建一个二维数组 dist&#xff0c;其中 dist[i][j] 表示从节点 i 到节点…

嵌入式实时操作系统的设计与开发(调度策略学习)

将调度分为两层&#xff0c;上层为策略&#xff0c;下层为机制&#xff0c;并且采用策略与机制分离的设计原则&#xff0c;可以方便灵活地扩展调度策略&#xff0c;而不改变底层的调度机制。 调度策略就是如何确定线程的CPU、优先级prio等参数&#xff0c;线程是按照FIFO&…