Spring Boot整合 Spring Security

 Spring Boot整合

1、RBAC 权限模型

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

在RBAC模型里面,有3个基础组成部分,分别是:用户、角色和权限,它们之间的关系如下图所示

SELECT * FROM sec_permission;
SELECT * FROM sec_role_permission ;
SELECT * FROM sec_role;
SELECT * FROM sec_user_role;
SELECT * FROM sec_user;

2、启动器依赖引入

啥配置也没做,啥类也没写。只是增加了一个启动器依赖

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

重新访问首页:http://localhost:8080/


3、用户名密码

默认:

用户名默认:user

密码在服务启动时打印在了控制台

自定义:

 当然我们也可以通过application.yml指定配置用户名密码

  • security.user.name 指定默认的用户名,默认为user.

  • security.user.password 默认的用户密码.

spring:
    security:
      user:
        name: admin
        password: admin

关闭security验证:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().permitAll().and().logout().permitAll();//配置不需要登录验证
    }
}

WebSecurityConfigurerAdapter 是由Spring Security提供的Web应用安全配置的适配器

WebSecurityConfigurerAdapter 是一个适配器类,允许开发者通过重写特定的方法来自定义其 Web 安全配置

创建一个配置类WebSecurityConfig继承WebSecurityConfigurerAdapter这个抽象类并重写configure(HttpSecurity http)方法,可以精确地定义哪些URL可以由哪些角色访问。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() // 表单方式
                .and()
                .authorizeRequests() // 授权配置
                .anyRequest().authenticated(); //所有未匹配的请求都需要用户进行身份验证
    }
}

Spring Security提供了这种链式的方法调用。上面配置指定了认证方式为表单登录,并且所有请求都需要进行认证。

HttpSecurity 是 Spring Security 中用于构建安全配置的一个类。通过该类,开发者可以配置许多与 HTTP 安全相关的选项,如认证、授权、CORS、CSRF 保护等

.formLogin() 是 HttpSecurity 类的一个方法,用于启用基于表单的身份验证。当你调用这个方法时,Spring Security 会自动配置登录表单的相关设置,如登录页面的 URL、登录成功和失败的处理等。你可以进一步定制这些设置,以适应你的应用程序需求。

-------------------------------

http.authorizeRequests() 是 HttpSecurity 类的一个方法,用于定义 URL 的访问权限。通过该方法,你可以指定哪些 URL 需要特定的角色或权限才能访问,哪些 URL 可以公开访问等。

--------------

.anyRequest().authenticated() 表示所有未匹配的请求都需要用户进行身份验证。


4、基于数据库的登录认证

Spring Security支持通过实现UserDetailsService接口的方式来提供用户认证授权信息。主要功能:根据用户名查询用户信息

@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private PermissionDao permissionDao;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //通过用户名从数据库获取用户信息
        User user = userDao.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("未找到用户信息 : " + username));
        //定义权限列表
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("a"));
        authorities.add(new SimpleGrantedAuthority("b"));
        authorities.add(new SimpleGrantedAuthority("c"));
        //返回spring security的User对象
        //user.getPassword() 数据库中的密码已经是密文存储
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
    }
}

返回值类型是UserDetails,我们可以直接使用Spring Security提供的UserDetails接口实现类org.springframework.security.core.userdetails.User


5、授权GrantedAuthority

GrantedAuthority则表示用户验证通过后被授予的权限。

SimpleGrantedAuthority

SimpleGrantedAuthority是默认的授权实现,它只存储权限(存储授予Authentication对象的权限的String表示形式),是一种简易的授权实现。

  • GrantedAuthority:直译"授予权限"
  • Authentication:直译"验证"

给我的感觉就是权限就是一个字符串,难道什么样的字符串都行吗?为啥定义的这么模糊

那我们就姑且给他"a","b","c"。。看看它怎么说

AuthorityUtils:此类一般用于UserDetailsService的实现类中的loadUserByUsername方法

作用为给user账户添加一个或多个权限,用逗号分隔,底层调用的是createAuthorityList方法,唯一区别在于此方法把所有的权限包含进一个字符串参数中,只不过用逗号分隔。

@Service
public class UserDetailsServiceImpl implements UserDetailsService{
	
	@Autowired
	PasswordEncoder passwordEncoder;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//比较密码
		String pass=passwordEncoder.encode("123");//加密
		return new User(username,pass,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
	}
	
}

createAuthorityList

将权限转换为List,如

@Service
public class UserDetailsServiceImpl implements UserDetailsService{
		
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		List<GrantedAuthority> list=AuthorityUtils.createAuthorityList("admin","normal");//一个权限一个参数
		return new User(username,pass,list);
	}
}

1


6、配置类中配置

实际项目中我们不会把密码明文存储在数据库中。只需要使用把BCryptPasswordEncoder对象注入Spring容器中,SpringSecurity就会使用该PasswordEncoder来进行密码校验

Spring Security实现的BCryptPasswordEncoder已经足够强大,它对相同的密码进行加密后可以生成不同的结果

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        //使用默认的BCryptPasswordEncoder加密方案
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置用户详细信息的服务和密码编码器
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //数据库读取的用户进行身份认证
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() // 表单方式
                .and()
                .authorizeRequests() // 授权配置
                .anyRequest().authenticated(); //所有未匹配的请求都需要用户进行身份验证
    }
}

Spring Security中的BCryptPasswordEncoder方法采用SHA-256 +随机盐+密钥对密码进行加密。SHA系列是Hash算法,不是加密算法,使用加密算法意味着可以解密(这个与编码/解码一样),但是采用Hash处理,其过程是不可逆的。

1)加密(encode):注册用户时,使用SHA-256+随机盐+密钥把用户输入的密码进行hash处理,得到密码的hash值,然后将其存入数据库中。

2)密码匹配(matches):用户登录时,密码匹配阶段并没有进行密码解密(因为密码经过Hash处理,是不可逆的),而是使用相同的算法把用户输入的密码进行hash处理,得到密码的hash值,然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同,说明用户输入的密码正确。

再次访问接口:http://127.0.0.1:8089/hello

使用账号密码登录 admin/123456


7、权限控制

Spring Security支持方法级别的权限控制。在此机制上,我们可以在任意层的任意方法上加入权限注解,加入注解的方法将自动被Spring Security保护起来,仅仅允许特定的用户访问,从而还到权限控制的目的

@PreAuthorize() 该注解用于方法前验证权限

//使用权限注解标明只有拥有“admin”权限的人才能访问:       

@PreAuthorize("hasAuthority('admin')")
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String sayHello() {
        return "hello";
    }

    @RequestMapping("/a")
    @PreAuthorize("hasAuthority('a')")
    public String sayA() {
        return "aaaaa";
    }

    @RequestMapping("/d")
    @PreAuthorize("hasAuthority('d')")
    public String sayB() {
        return "ddddd";
    }
}

Spring Security默认是禁用注解的,要想开启注解,要在继承WebSecurityConfigurerAdapter的类加@EnableGlobalMethodSecurity()注解,并在该类中将AuthenticationManager定义为Bean。说实话我没有注入AuthenticationManager这个bean的时候,也做到了权限校验。。这到底有啥用?

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        //使用默认的BCryptPasswordEncoder加密方案
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 配置用户详细信息的服务和密码编码器
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //数据库读取的用户进行身份认证
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() // 表单方式
                .and()
                .authorizeRequests() // 授权配置
                .anyRequest().authenticated(); //所有未匹配的请求都需要用户进行身份验证
    }
}

我们看到@EnableGlobalMethodSecurity 分别有prePostEnabled 、securedEnabled、jsr250Enabled三个字段,其中每个字段代码一种注解支持,默认为false,true为开启

重新登录访问。记得之前我随便给的权限字符串a,b,c。。。访问a是没问题的

访问d会返回403错误码。

自定义权限不足处理器来处理权限不足时候的操作


8、Session管理

用户登录成功后,信息保存在服务器Session中。如Tomcat

登录后,可以看到cookie中存储了JSESSIONID的cookie。

Session超时设置

如可以设置session有效期为1小时

server:
  session:
    timeout: 3600

这时候,就涉及到一个session共享

当应用集群部署的时候,用户在A应用上登录认证了,后续通过负载均衡可能会把请求发送到B应用,而B应用服务器上并没有与该请求匹配的认证Session信息,所以用户就需要重新进行认证

Spring Security默认的退出登录URL为/logout

自定义配置

1、请求授权

http.authorizeRequests()主要是对url进行访问权限控制,通过这个方法来实现url授权操作。支持链式写法,举例:
 http.authorizeRequests() .url匹配规则1.权限控制方法1 .url匹配规则2.权限控制方法2...

​在所有匹配规则中取所有规则的交集。配置顺序影响了之后授权效果。

越是具体的应该放在前面,越是笼统的应该放到后面。

anyRequest(),表示匹配所有的url请求

如下图表示:所有请求都不需要验证

与之相反的如下,表示所有请求都需要登录验证

antMatcher(String regx)

antMatcher(String regx),传递一个ant表达式参数,表示匹配所有满足ant表达式的请求

ant表达式中特殊字符解释

举例:

/a/* :匹配 /a/ 下的所有路径,不递归,如: /a/b,/a/c,但不包括/a/b/c

/a/**:匹配 /a/ 下所有路径,递归,如 :/a/b,/a/b/c,/a/b/c/d

/a/a?c:匹配/a/ 下路径中a开头,c结尾,中间按含任意字符的路径,如:/a/adc


2、访问控制方法

permitAll()    表示所匹配的URL任何人都允许访问
anonymous()    表示可以匿名访问匹配的URL。和permitAll()效果类似,只是设置为anonymous()的url会执行filterChain中的filter
denyAll()    表示所匹配的URL都不允许被访问。
authenticated()    表示所匹配的URL都需要被认证才能访问
rememberMe()    允许通过remember-me登录的用户访问
access()    SpringEl表达式结果为true时可以访问
fullyAuthenticated()    用户完全认证可以访问(非remember-me下自动登录)
hasRole()    如果有参数,参数表示角色,则其角色可以访问
hasAnyRole()    如果有参数,参数表示角色,则其中任何一个角色可以访问
hasAuthority()    如果有参数,参数表示权限,则其权限可以访问
hasAnyAuthority()    如果有参数,参数表示权限,则其中任何一个权限可以访问
hasIpAddress()    如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问


Spring Security OAuth2

1、什么是OAuth

OAuth是一种用来规范令牌(Token)发放的授权机制,主要包含了四种授权模式:授权码模式、简化模式、密码模式和客户端模式

OAuth相关的名词

  1. Third-party application 第三方应用程序,比如这里的虎牙直播;

  2. HTTP service HTTP服务提供商,比如这里的QQ(腾讯);

  3. Resource Owner 资源所有者,就是QQ的所有人,你;

  4. User Agent 用户代理,这里指浏览器;

  5. Authorization server 认证服务器,这里指QQ提供的第三方登录服务;

  6. Resource server 资源服务器,这里指虎牙直播提供的服务,比如高清直播,弹幕发送等(需要认证后才能使用)。

Spring Security OAuth2主要包含认证服务器和资源服务器这两大块的实现:

认证服务器主要包含了四种授权模式的实现和Token的生成与存储

资源服务器主要是在Spring Security的过滤器链上加了OAuth2AuthenticationProcessingFilter过滤器,即使用OAuth2协议发放令牌认证的方式来保护我们的资源


2、认证授权服务器

创建认证服务器很简单,只需要在Spring Security的配置类上使用@EnableAuthorizationServer注解标注即可

使用 @EnableAuthorizationServer 注解,在应用中自动开启和配置 Spring Security OAuth 的授权服务组件。

 @EnableAuthorizationServer 注解主要是导入两个配置类,分别是:

  • AuthorizationServerEndpointsConfiguration,这个配置类主要配置授权端点,获取token的端点。大家就把对应的端点想象成controller即可,在这个controller下开放了若干个@RequestMapping,比如常见的有:/oauth/authorize(授权路径)/oauth/token(获取token)
  • AuthorizationServerSecurityConfiguration,主要是做spring-security的安全配置

3、资源服务器

资源服务器的配置也很简单,只需要在配置类上使用@EnableResourceServer注解标注即可:

通过资源服务器来保护我们指定的资源,必须在获取授权认证的时候才能访问。在SpringBoot当中,我们可以通过@EnableResourceServer注解来开启此功能。

    @Configuration
    @EnableResourceServer
    public class ResourceConfigure extends ResourceServerConfigurerAdapter {
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                    .and().authorizeRequests().antMatchers("/free/**").permitAll().and()
                    .authorizeRequests().anyRequest().authenticated()
                    .and().formLogin().permitAll();//必须认证过后才可以访问
        }
    }
    

JsonWebToken

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;

1、JWT介绍

JWT.io 是一个方便、快速、实用的 JWT 在线解析工具,在进行开发和调试时可以帮助我们解析和验证 JWT。JSON Web Tokens - jwt.io

JWT(Json Web Token)就是一个字符串,由三部分构成:

  • Header(头部)

  • Payload(载荷)

  • Signature(签名)

头 Header:  加密算法(arg)+类型(typ)

然后将Header进行Base64编码(该编码是可以对称解码的),构成了第一部分。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷就是存放有效信息的地方。定义细节如下:

有效载荷 Payload

JWT指定七个默认载荷字段供选择。

iss:发行人

exp:过期时间

sub:主题

aud:用户

nbf:在此之前不可用

iat:发布时间

jti:JWT ID用于标识该JWT

除以上默认字段外,我们还可以自定义载荷私有字段,如(用户id、头像地址、昵称)

{
"nickname": "xiaoyumao",
"id": "1001",
"avatar": "yy.jpg"
}

然后将其进行Base64编码,得到Jwt的第二部分:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

签名 Signature

这个部分需要Base64编码后的Header和Base64编码后的Payload使用 . 连接组成的字符串,然后通过Header中声明的加密方式进行加密

然后就构成了jwt的第三部分。密码$secret 仅仅为保存在服务器中,并且不能向用户公开。

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');

2、生成jwt令牌

JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.0.6.RELEASE</version>
</dependency>

生成jwt令牌,即base64编码后的字符串

  • JwtBuilder setClaims(Claims claims);
  • JwtBuilder setClaims(Map<String, Object> claims);
    不能就是说,我们也可以直接传入map值对象。
@SpringBootTest
public class JWTtest {
    @Test
    public void contextLoads() {
        //构建jwt 字符串
        String jwt = Jwts.builder()
                //请求头   加密算法和令牌类型
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "jwt")
                //载荷
                .setSubject("GMALL-TOKEN") //主题
                .setExpiration(new Date(System.currentTimeMillis() + 60 * 1000 * 60)) //什么时候过期
                .claim("nickname", "xiaoyumao")
                .claim("id", "1001")
                .claim("avatar", "yy.jpg")
                //签名
                .signWith(SignatureAlgorithm.HS256, "123456")
                .compact();
        System.out.println(jwt);
    }
}

eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJzdWIiOiJHTUFMTC1UT0tFTiIsImV4cCI6MTY3NDIwODcyMiwibmlja25hbWUiOiJ4aWFveXVtYW8iLCJpZCI6IjEwMDEiLCJhdmF0YXIiOiJ5eS5qcGcifQ.5WFPxldISkQ8RxGBGFGTtrdjpzXLe6TdHKkc6h3aROo


3、解析jwt字符串

@Test
public void test(){
    String s = "";//s是刚刚生成的jwt字符串
    Jwt jwt = Jwts.parser().setSigningKey("123456")
            .parse(s);
    DefaultClaims body = (DefaultClaims) jwt.getBody();
    System.out.println(body.get("id"));
    System.out.println(body.get("nickname"));
    System.out.println(body.get("avatar"));
}

后端将来只要验证jwt有效载荷数据使用秘钥再次加密生成的签名和jwt的签名 就能判断数据是否被篡改;就算签名验证成功了,再验证过期时间 如果过期了也报错


4、JWT工具类生成token

JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token并且这个JWT token带有签名信息,接收后可以校验是否被篡改。

一般是将它放入HTTP请求的Header Authorization字段中。

1.构建公钥、私钥文件,这个secret你跟别人越不一样,就越安全

    String publicKeyFile = "E:\\rsa.pub";
    String privateKeyFile = "E:\\rsa.pri";
    String secret = "`qa*97()'!dasfa213";

    @Test
    void contextLoads() throws Exception {
        //构建公钥私钥文件
        RsaUtils.generateKey(publicKeyFile,privateKeyFile , secret);
    }

2.加载公钥私钥文件生成对象

PublicKey publicKey;
PrivateKey privateKey;
int expire = 60;
//加载公钥私钥文件生成对象
@Test
void test1() throws Exception {
    publicKey = RsaUtils.getPublicKey(publicKeyFile);
    privateKey = RsaUtils.getPrivateKey(privateKeyFile);
}

3.使用私钥对象生成jwt字符串,map是载荷

//生成jwt
@Test
void generateJwt() throws Exception {
    Map<String, Object> map = new HashMap<>();
    map.put("userId","1001");
    map.put("username","xiaoyumao");
    map.put("avatar","mengmeng.jpg");
    //使用私钥对象生成jw  map是载荷
    String token = JwtUtils.generateToken(map, privateKey, expire);
    System.out.println(token);
}

4.使用公钥对象解析jwt字符串

 @Test
 void parseJwt() throws Exception {
     String jwt = "eyJhbGciOiJ...";//上一步生成的jwt字符串,很长很长,这里简写
     Map<String, Object> map = JwtUtils.getInfoFromToken(jwt, publicKey);
     System.out.println(map);
 }

公钥或者私钥任何一个不存在,都要重新构建密钥对


5、JwtConfig

application.yml

jwt:
  config:
    key: xkcoding
    ttl: 600000
    remember: 604800000

创建配置绑定类

@ConfigurationProperties(prefix = "jwt.config")
@Data
public class JwtConfig {
    /**
     * jwt 加密 key,默认值:xkcoding.
     */
    private String key = "xkcoding";

    /**
     * jwt 过期时间,默认值:600000 {@code 10 分钟}.
     */
    private Long ttl = 600000L;

    /**
     * 开启 记住我 之后 jwt 过期时间,默认值 604800000 {@code 7 天}
     */
    private Long remember = 604800000L;
}

加密key,在生产签名时使用

@EnableConfigurationProperties(JwtConfig.class)
@Configuration
@Slf4j
public class JwtUtil {
    @Autowired
    private JwtConfig jwtConfig;

//.signWith(SignatureAlgorithm.HS256, jwtConfig.getKey())

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧工地源码:为施工企业提供专业落地的解决方案

智慧工地利用物联网、大数据、AI等核心技术&#xff0c;实时采集现场数据&#xff0c;自动分析&#xff0c;精准分析、智能决策、科学评价&#xff0c;形成一套数据驱动的新型管理模式。为施工企业提供生产提效、安全可控、成本节约的项目管理解决方案&#xff0c;提升项目部管…

每周一算法:树形动态规划

树形动态规划 树形动态规划一般用于处理求树上最优值的问题。大多数动态规划问题都是在一维二维这种规则的背景下的&#xff0c;可以解决的问题比较局限&#xff0c;而树作为一种特殊的图&#xff0c;可以描述比较复杂的关系&#xff0c;再加上树的递归定义&#xff0c;是一种…

linux系统的u盘/mmc/sd卡等的支持热插拔和自动挂载行为

1.了解mdev mdev是busybox自带的一个简化版的udev。udev是从Linux 2.6 内核系列开始的设备文件系统&#xff08;DevFS&#xff09;的替代品&#xff0c;是 Linux 内核的设备管理器。总的来说&#xff0c;它取代了 devfs 和 hotplug&#xff0c;负责管理 /dev 中的设备节点。同时…

openHarmony添加system_basic权限安装报错

openHarmony添加system_basic权限安装报错 12/14 13:49:57: Install Failed: [Info]App install path:D:\huawei\project\FCTTest\entry\build\default\outputs\default\entry-default-signed.hap, queuesize:0, msg:error: failed to install bundle. error: install failed …

【ET8框架入门】0.ET框架介绍

ET8 新特性 多线程多进程架构,架构更加灵活强大&#xff0c;多线程设计详细内容请看多线程设计课程抽象出纤程(Fiber)的概念&#xff0c;类似erlang的进程&#xff0c;非常轻松的创建多个纤程&#xff0c;利用多核&#xff0c;仍然是单线程开发的体验纤程调度: 主线程&#xf…

LeetCode Hot100 23.合并K个升序链表

题目&#xff1a; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 方法&#xff1a;分治&#xff0c;类似于归并 class Solution {public ListNode mergeKLists(ListNode[] lists) {return mer…

MySQL:从MySQL看主从架构高可用性实现

目录 1 主备延迟 1.1 主备延迟 1.2 主备延迟的来源 1.2.1 主备机性能有差距 1.2.2 备库压力大 1.2.3 大事务 1.3 主备延迟的排查思路 3&#xff09;查看MySQL状态 2 主备切换策略 2.1 可靠性优先策略 2.2 可用性优先策略 2.3 常见切换技术 从进入互联网时代开始&a…

深度学习第5天:GAN生成对抗网络

☁️主页 Nowl &#x1f525;专栏 《深度学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​​ 文章目录 一、GAN1.基本思想2.用途3.模型架构 二、具体任务与代码1.任务介绍2.导入库函数3.生成器与判别器4.预处理5.模型训练6.图片生成7.不同训练轮次的结果对比 一…

KylinV10 将项目上传至 Github

KylinV10 将项目上传至 Github 银河麒麟操作系统 V10 是在 Ubuntu 的基础上开发的&#xff0c;所以适用于 Ubuntu 的也适用于 KylinV10 一般上传至 GitHub&#xff0c;有两种方式&#xff0c;一种是 HTTPS&#xff0c;一种是 SSH&#xff0c;但是在 KylinV10 操作系统 HTTPS 的…

大数据----31.hbase安装启动

二.Hbase安装 先前安装&#xff1a; Zookeeper 正常部署 首先保证 Zookeeper 集群的正常部署&#xff0c;并启动之。 三台机器都执行&#xff1a;zkServer.sh startHadoop 正常部署 Hadoop 集群的正常部署并启动。 主节点上进行 &#xff1a;start-all.sh 1.HBase 的获取 一定…

【Python网络爬虫入门教程1】成为“Spider Man”的第一课:HTML、Request库、Beautiful Soup库

Python 网络爬虫入门&#xff1a;Spider man的第一课 写在最前面背景知识介绍蛛丝发射器——Request库智能眼镜——Beautiful Soup库 第一课总结 写在最前面 有位粉丝希望学习网络爬虫的实战技巧&#xff0c;想尝试搭建自己的爬虫环境&#xff0c;从网上抓取数据。 前面有写一…

c#读取XML文件实现晶圆wafermapping显示demo计算电机坐标以便控制电机移动

c#读取XML文件实现晶圆wafermapping显示 功能&#xff1a; 1.读取XML文件&#xff0c;显示mapping图 2.在mapping视图图标移动&#xff0c;实时查看bincode,x,y索引与计算的电机坐标 3.通过设置wafer放在平台的位置x,y轴电机编码值&#xff0c;相机在wafer的中心位置&#…

IDEA删除最近打开的文件记录

IDEA删除最近打开的文件记录 遇见问题&#xff1a;如何删除IDEA中最近打开的文件记录 解决方法 先关闭IDEA 找到 recentProjects.xml 文件 windows 位置&#xff1a;&#xff08;AppData是隐藏文件夹&#xff09; 1.C:\Users\电脑用户名\AppData\Roaming\JetBrains\IntelliJIde…

jpa 修改信息拦截

实现目标springbootJPA 哪个人&#xff0c;修改了哪个表的哪个字段&#xff0c;从什么值修改成什么值 Component // 必须加 Slf4j Configurable(autowire Autowire.BY_TYPE) public class AuditingEntityListener {// 线程变量&#xff0c;保存修改前的 objectprivate Thre…

SpringBoot运维中的高级配置

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

Navicat16 无限试用 亲测有效

Navicat16 无限试用 亲测有效 亲测有效&#xff01;&#xff01;&#xff01; 吐槽下&#xff0c;有的用不了&#xff0c;有的是图片&#xff0c;更甚者还有收费的&#xff0c;6的一批 粘贴下面的代码&#xff0c;保存到桌面&#xff0c;命名为 trial-navicat16.bat echo off…

Web安全-SQL注入常用函数(二)

★★实战前置声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将其信息做其他用途&#xff0c;由用户承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、MySQL数据库构成 初始化安装MySQL数据库后(…

从零开始搭建企业管理系统(七):RBAC 之用户管理

RBAC 之用户管理 创建表&#xff08;Entity&#xff09;用户表角色表权限表用户角色表关系注解ManyToMany 角色权限表 接口开发UserControllerUserServiceUserServiceImplUserRepository 问题解决update 更新问题懒加载问题JSON 循环依赖问题 根据上一小结对表的设计&#xff0…

基于ssm高校食堂订餐系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本高校食堂订餐系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

服务器数据恢复-EqualLogic PS存储硬盘坏道导致存储不可用的数据恢复案例

服务器数据恢复环境&#xff1a; 一台DELL EqualLogic PS系列存储&#xff0c;存储中有一组由16块SAS硬盘组成的RAID5。上层是VMFS文件系统&#xff0c;存放虚拟机文件。存储上层分了4个卷。 服务器故障&检测&#xff1a; 存储上有2个硬盘指示灯显示黄色&#xff0c;磁盘出…