6.2 认证授权模块 - 继承JWT、网关认证

认证授权模块 - 继承JWT、网关认证

文章目录

  • 认证授权模块 - 继承JWT、网关认证
  • 一、JWT
    • 1.1 普通令牌
    • 1.2 JWT 令牌介绍
    • 1.3 测试生成JWT 令牌
      • 1.3.1 TokenConfig
      • 1.3.2 授权服务器配置 AuthorizationServer
      • 1.3.3 WebSecurityConfig 安全管理配置
      • 1.3.4 返回信息
    • 1.4 资源服务集成 JWT
      • 1.4.1 Maven
      • 1.4.2 配置类
        • 1.4.2.1 资源服务配置 ResourceServerConfig
        • 1.4.2.2 TokenConfig
  • 二、网关认证
    • 2.1 技术方案
    • 2.2 网关认证实现
      • 2.2.1 Maven 依赖
      • 2.2.2 网关认证配置类
        • 2.2.2.1 SecurityConfig 安全配置类
        • 2.2.2.2 TokenConfig
        • 2.2.2.3 网关认证过虑器 GatewayAuthFilter
        • 2.2.2.4 错误响应参数包装 RestErrorResponse
        • 2.2.2.5 配置白名单

一、JWT

客户端申请到令牌,接下来客户端携带令牌去访问资源,到资源服务器将会校验令牌的合法性

令牌其实就是文本数字拼装出来的一个序列号

过滤器与拦截器 - 登录校验与登录认证(JWT令牌技术)

1.1 普通令牌

资源服务器如何校验令牌的合法性

以OAuth2的密码模式为例进行说明

从第4步开始说明:

1、客户端携带令牌访问资源服务获取资源

2、资源服务远程请求认证服务校验令牌的合法性

3、如果令牌合法资源服务向客户端返回资源

image-20240123230022675

存在一个问题

校验令牌需要远程请求认证服务,客户端的每次访问都会远程校验,执行性能低

也就是上图的第五步

如果能够让资源服务自己校验令牌的合法性将省去远程请求认证服务的成本,提高了性能

image-20240123230238141

如何解决上边的问题,实现资源服务自行校验令牌

令牌采用JWT格式即可解决上边的问题,用户认证通过后会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权

1.2 JWT 令牌介绍

  • JWT 介绍

JSON Web Token(JWT)是一种使用JSON格式传递数据的网络令牌技术,它是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任,它可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止内容篡改

  • 使用JWT可以实现无状态认证,什么是无状态认证

基于session

传统的基于session的方式是有状态认证,用户登录成功将用户的身份信息存储在服务端,这样加大了服务端的存储压力,并且这种方式不适合在分布式系统中应用。

如下图,当用户访问应用服务,每个应用服务都会去服务器查看session信息,如果session中没有该用户则说明用户没有登录,此时就会重新认证,而解决这个问题的方法是Session复制、Session黏贴

image-20240123232330883

基于令牌技术

基于令牌技术在分布式系统中实现认证则服务端不用存储session,可以将用户身份信息存储在令牌中,用户认证通过后认证服务颁发令牌给用户,用户将令牌存储在客户端,去访问应用服务时携带令牌去访问,服务端从jwt解析出用户信息。这个过程就是无状态认证

image-20240123232426582

  • JWT令牌的优点

1、jwt基于json,非常方便解析

2、可以在令牌中自定义丰富的内容,易扩展

3、通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高

4、资源服务使用JWT可不依赖认证服务即可完成授权

  • JWT令牌的缺点

JWT令牌较长,占存储空间比较大

如下所示

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2NjQyNTQ2NzIsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6Ijg4OTEyYjJkLTVkMDUtNGMxNC1iYmMzLWZkZTk5NzdmZWJjNiIsImNsaWVudF9pZCI6ImMxIn0.wkDBL7roLrvdBG2oGnXeoXq-zZRgE9IVV2nxd-ez_oA
  • JWT令牌的组成部分

JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

  1. Header 部分

头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)

将下边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分

  {"alg": "HS256","typ": "JWT"}
  1. Payload 部分

第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的信息字段,比如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段

此部分不建议存放敏感信息,因为此部分可以解码还原原始内容

最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分

  {"sub": "1234567890","name": "456","admin": true}
  1. Signature 部分

第三部分是签名,此部分用于防止jwt内容被篡改

这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明的签名算法进行签名

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

base64UrlEncode(header):jwt令牌的第一部分

base64UrlEncode(payload):jwt令牌的第二部分

secret:签名所使用的密钥

为什么JWT可以防止篡改

第三部分使用签名算法对第一部分和第二部分的内容进行签名,常用的签名算法是 HS256,常见的还有md5,sha 等

签名算法需要使用密钥进行签名,密钥不对外公开,并且签名是不可逆的,如果第三方更改了内容那么服务器验证签名就会失败,要想保证验证签名正确必须保证内容、密钥与签名前一致

image-20240123233428307

从上图可以看出认证服务和资源服务使用相同的密钥,这叫对称加密,对称加密效率高,如果一旦密钥泄露可以伪造jwt令牌。

JWT还可以使用非对称加密,认证服务自己保留私钥,将公钥下发给受信任的客户端、资源服务,公钥和私钥是配对的,成对的公钥和私钥才可以正常加密和解密,非对称加密效率低但相比对称加密非对称加密更安全一

1.3 测试生成JWT 令牌

1.3.1 TokenConfig

将普通令牌的配置改成JWT令牌的配置

@Configuration
public class TokenConfig {// 对称加密的密钥private String SIGNING_KEY = "mq123";//package org.springframework.security.oauth2.provider.token;@AutowiredTokenStore tokenStore;//    @Bean
//    public TokenStore tokenStore() {
//        //使用内存存储令牌(普通令牌)
//        return new InMemoryTokenStore();
//    }// 生成JWT的@Autowiredprivate JwtAccessTokenConverter accessTokenConverter;@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}//令牌管理服务@Bean(name = "authorizationServerTokenServicesCustom")public AuthorizationServerTokenServices tokenService() {DefaultTokenServices service = new DefaultTokenServices();service.setSupportRefreshToken(true);//支持刷新令牌service.setTokenStore(tokenStore);//令牌存储策略TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));service.setTokenEnhancer(tokenEnhancerChain);service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天return service;}
}

1.3.2 授权服务器配置 AuthorizationServer

/*** @description 授权服务器配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {@Resource(name = "authorizationServerTokenServicesCustom")private AuthorizationServerTokenServices authorizationServerTokenServices;@Autowiredprivate AuthenticationManager authenticationManager;//客户端详情服务@Overridepublic void configure(ClientDetailsServiceConfigurer clients)throws Exception {clients.inMemory()// 使用in-memory存储.withClient("XcWebApp")// client_id.secret("XcWebApp")//客户端密钥
//                .secret(new BCryptPasswordEncoder().encode("XcWebApp"))//客户端密钥.resourceIds("xuecheng-plus")//资源列表.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials.scopes("all")// 允许的授权范围.autoApprove(false)//false跳转到授权页面//客户端接收授权码的重定向地址.redirectUris("http://www.51xuecheng.cn");}//令牌端点的访问配置@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager)//认证管理器.tokenServices(authorizationServerTokenServices)//令牌管理服务.allowedTokenEndpointRequestMethods(HttpMethod.POST);}//令牌端点的安全配置@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) {security.tokenKeyAccess("permitAll()")       //oauth/token_key是公开.checkTokenAccess("permitAll()")     //oauth/check_token公开.allowFormAuthenticationForClients() //表单认证(申请令牌);}}

1.3.3 WebSecurityConfig 安全管理配置

/*** @description 安全管理配置*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//配置用户信息服务@Beanpublic UserDetailsService userDetailsService() {//这里配置用户信息,这里暂时使用这种方式将用户存储在内存中InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());return manager;}@Beanpublic PasswordEncoder passwordEncoder() {
//        //密码为明文方式return NoOpPasswordEncoder.getInstance();
//        return new BCryptPasswordEncoder();}//配置安全拦截机制@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/r/**").authenticated()//访问/r开始的请求需要认证通过.anyRequest().permitAll()//其它请求全部放行.and().formLogin().successForwardUrl("/login-success");//登录成功跳转到/login-success}@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}}

1.3.4 返回信息

{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2NjQzMzE2OTUsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6ImU5ZDNkMGZkLTI0Y2ItNDRjOC04YzEwLTI1NmIzNGY4ZGZjYyIsImNsaWVudF9pZCI6ImMxIn0.-9SKI-qUqKhKcs8Gb80Rascx-JxqsNZxxXoPo82d8SM","token_type": "bearer","refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJlOWQzZDBmZC0yNGNiLTQ0YzgtOGMxMC0yNTZiMzRmOGRmY2MiLCJleHAiOjE2NjQ1ODM2OTUsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6ImRjNTRjNTRkLTA0YTMtNDIzNS04MmY3LTFkOWZkMmFjM2VmNSIsImNsaWVudF9pZCI6ImMxIn0.Wsw1Jc-Kd_GFqEugzdfoSsMY6inC8OQsraA21WjWtT8","expires_in": 7199,"scope": "all","jti": "e9d3d0fd-24cb-44c8-8c10-256b34f8dfcc"
}

1、access_token,生成的jwt令牌,用于访问资源使用。

2、token_type,bearer是在RFC6750中定义的一种token类型,在携带jwt访问资源时需要在head中加入bearer jwt令牌内容

3、refresh_token,当jwt令牌快过期时使用刷新令牌可以再次生成jwt令牌。

4、expires_in:过期时间(秒)

5、scope,令牌的权限范围,服务端可以根据令牌的权限范围去对令牌授权。

6、jti:令牌的唯一标识。

1.4 资源服务集成 JWT

下面我们要实现携带令牌访问资源服务

拿到了jwt令牌下一步就要携带令牌去访问资源服务中的资源,本项目各个微服务就是资源服务

比如:内容管理服务,客户端申请到jwt令牌,携带jwt去内容管理服务查询课程信息,此时内容管理服务要对jwt进行校验,只有jwt合法才可以继续访问

image-20240124220411248

下面的"Bearer"是Http协议中的一个规范,就是用来使用OAuth2协议去认证的时候使用的一个标志,“Bearer”+"空格"后面的内容就是令牌的内容

image-20240124222414788

1.4.1 Maven

在内容管理服务的content-api工程中添加依赖

<!--认证相关-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

1.4.2 配置类

content-api工程添加配置类

1.4.2.1 资源服务配置 ResourceServerConfig
/*** @author Mr.M* @description 资源服务配置*/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {//资源服务标识(我们当初发令牌的时候,我们指定了资源的名称)public static final String RESOURCE_ID = "xuecheng-plus";@AutowiredTokenStore tokenStore;@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(RESOURCE_ID)//资源 id.tokenStore(tokenStore).stateless(true);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests()// 所有"/r/**"、"/course/**"的请求必须认证通过。这个认证注释掉就可以了,因为我们的认证是在网关做的//.antMatchers("/r/**", "/course/**").authenticated().anyRequest()// 除了上面以外的全部放行.permitAll();}
}
1.4.2.2 TokenConfig
@Configuration
public class TokenConfig {// 秘钥(这个地方秘钥要和auth工程的密钥相同,因为我们是对称加密)String SIGNING_KEY = "mq123";//    @Bean
//    public TokenStore tokenStore() {
//        //使用内存存储令牌(普通令牌)
//        return new InMemoryTokenStore();
//    }@Autowiredprivate JwtAccessTokenConverter accessTokenConverter;//JWT方式@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}
}

二、网关认证

网关的作用

  • 路由转发
  • 认证

校验JWT令牌的合法性

  • 维护一份白名单

2.1 技术方案

首先就是完善下图的流程,因为下图中缺少网关

image-20240124224210788

加上网关并完善后如下图所示

image-20240124224425088

所有访问微服务的请求都要经过网关,在网关进行用户身份的认证可以将很多非法的请求拦截到微服务以外,这叫做网关认证

  • 下边需要明确网关的职责

1、网站白名单维护

针对不用认证的URL全部放行。

2、校验jwt的合法性

除了白名单剩下的就是需要认证的请求,网关需要验证jwt的合法性,jwt合法则说明用户身份合法,否则说明身份不合法则拒绝继续访问

  • 网关负责授权吗

网关不负责授权,对请求的授权操作在各个微服务进行,因为微服务最清楚用户有哪些权限访问哪些接口

2.2 网关认证实现

2.2.1 Maven 依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId>
</dependency>

2.2.2 网关认证配置类

2.2.2.1 SecurityConfig 安全配置类
/*** @description 安全配置类*/
@EnableWebFluxSecurity
@Configuration
public class SecurityConfig {//安全拦截配置@Beanpublic SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) {return http.authorizeExchange().pathMatchers("/**").permitAll().anyExchange().authenticated().and().csrf().disable().build();}}
2.2.2.2 TokenConfig
/*** @author Administrator* @version 1.0**/
@Configuration
public class TokenConfig {String SIGNING_KEY = "mq123";//    @Bean
//    public TokenStore tokenStore() {
//        //使用内存存储令牌(普通令牌)
//        return new InMemoryTokenStore();
//    }@Autowiredprivate JwtAccessTokenConverter accessTokenConverter;@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}}
2.2.2.3 网关认证过虑器 GatewayAuthFilter

一定要看懂这个玩意,我们需要在这里校验令牌是否合法

/*** @description 网关认证过虑器*/
@Component
@Slf4j
public class GatewayAuthFilter implements GlobalFilter, Ordered {//白名单private static List<String> whitelist = null;static {//加载白名单try (// 白名单的路径InputStream resourceAsStream = GatewayAuthFilter.class.getResourceAsStream("/security-whitelist.properties");) {Properties properties = new Properties();properties.load(resourceAsStream);Set<String> strings = properties.stringPropertyNames();whitelist= new ArrayList<>(strings);} catch (Exception e) {log.error("加载/security-whitelist.properties出错:{}",e.getMessage());e.printStackTrace();}}@Autowiredprivate TokenStore tokenStore;/*** 过滤方法*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String requestUrl = exchange.getRequest().getPath().value();AntPathMatcher pathMatcher = new AntPathMatcher();//TODO 1.首先判断请求的URL requestUrl是否在白名单当中//白名单放行for (String url : whitelist) {if (pathMatcher.match(url, requestUrl)) {// 属于白名单,直接放行return chain.filter(exchange);}}//TODO 请求的路径不在白名单当中,需要校验token的合法性//检查token是否存在String token = getToken(exchange);if (StringUtils.isBlank(token)) {// 此时token为空或nullreturn buildReturnMono("没有认证",exchange);}//TODO 运行到这里token肯定是有值的//判断是否是有效的tokenOAuth2AccessToken oAuth2AccessToken;try {// 读tokenoAuth2AccessToken = tokenStore.readAccessToken(token);// 判断token是否过期boolean expired = oAuth2AccessToken.isExpired();if (expired) {return buildReturnMono("认证令牌已过期",exchange);}return chain.filter(exchange);} catch (InvalidTokenException e) {// 运行到这里说明令牌被篡改了log.info("认证令牌无效: {}", token);return buildReturnMono("认证令牌无效",exchange);}}/*** 获取token*/private String getToken(ServerWebExchange exchange) {String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization");if (StringUtils.isBlank(tokenStr)) {return null;}String token = tokenStr.split(" ")[1];if (StringUtils.isBlank(token)) {return null;}return token;}private Mono<Void> buildReturnMono(String error, ServerWebExchange exchange) {ServerHttpResponse response = exchange.getResponse();String jsonString = JSON.toJSONString(new RestErrorResponse(error));byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8);DataBuffer buffer = response.bufferFactory().wrap(bits);response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));}@Overridepublic int getOrder() {return 0;}
}
2.2.2.4 错误响应参数包装 RestErrorResponse
/*** 错误响应参数包装*/
public class RestErrorResponse implements Serializable {private static final long serialVersionUID = 5472552994671223012L;private String errMessage;public RestErrorResponse(String errMessage){this.errMessage= errMessage;}public String getErrMessage() {return errMessage;}public void setErrMessage(String errMessage) {this.errMessage = errMessage;}
}
2.2.2.5 配置白名单
/auth/**=认证地址
/content/open/**=内容管理公开访问接口
/media/open/**=媒资管理公开访问接口

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

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

相关文章

《乱弹篇(十九)围炉诗话》

闲来无事&#xff0c;近日浏览中国古代文学书藉&#xff0c;读罢《新嫁娘词》中的一首五言绝句诗&#xff0c;觉得妙趣横生&#xff0c;艺术造诣甚高。今天恰逢春潮寒意还浓&#xff0c;气温很低&#xff0c;笔者雅兴勃发&#xff0c;便开足暖气&#xff0c;也附庸风雅地来一番…

WSL2配置Linux、Docker、VS Code、zsh、oh my zsh(附Docker开机自启设置)

0. 写在前面 本篇笔记来自于UP主麦兜搞IT的合集视频Windows10开发环境搭建中的部分内容 1. 安装WSL2 按照微软官方文档进行操作&#xff0c;当然也可以直接wsl --install 也可以按照 旧版手动安装的步骤 来进行操作 选择安装的是Ubuntu 20.04 LTS 注&#xff1a;WSL默认安装…

抖音视频提取软件使用功能|抖音视频下载工具

我们的抖音视频提取软件是一款功能强大、易于操作的工具&#xff0c;旨在解决用户在获取抖音视频时需要逐个复制链接、下载的繁琐问题。我们的软件支持通过关键词搜索和分享链接两种方式获取抖音视频&#xff0c;方便用户快速找到自己感兴趣的内容。 主要功能模块&#xff1a;…

计算机设计大赛 深度学习图像风格迁移

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

pytorch -- CIFAR10 完整的模型训练套路

网络结构 代码 # CIFAR 10完整的模型训练套路&#xff1a; import torch.optim import torchvision from torch import nn from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriterfrom model import *# 1. 准备数据集 train_data torch…

SSM框架学习笔记07 | Spring MVC入门

文章目录 1. HTTP协议2. Spring MVC2.1. 三层架构2.2. MVC&#xff08;解决表现层的问题&#xff09;2.3. 核心组件 3. Thymeleaf3.1. 模板引擎3.2. Thymeleaf3.3. 常用语法 代码 1. HTTP协议 网址&#xff1a;https://www.ietf.org/ &#xff08;官网网址&#xff09; https:…

dolphinscheduler单机版部署教程

文章目录 前言一、安装准备1. 安装条件2. 安装jdk3. 安装MySQL 二、安装dolphinscheduler1. 下载并解压dolphinscheduler2. 修改配置文件2.1 修改 dolphinscheduler_env.sh 文件2.2 修改 application.yaml 文件 3. 配置mysql数据源3.1 修改MySQL安全策略3.2 查看数据库3.3 创建…

使用Docker部署MinIO并结合内网穿透实现远程访问本地数据

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

Pytest教程:一种利用 Python Pytest Hook 机制的软件自动化测试网络数据抓包方法

随着计算机技术的发展&#xff0c;使得网络应用的数量不断增加&#xff0c;因此网络数据抓包成为了网络应用开发和测试中非常重要的一部分。目前&#xff0c;已有许多网络数据抓包工具可供使用&#xff0c;例如 Wireshark、Tcpdump、Fiddler 等&#xff0c;但这些工具需要手动配…

进程的学习

进程基本概念: 1.进程: 程序&#xff1a;存放在外存中的一段数据组成的文件 进程&#xff1a;是一个程序动态执行的过程,包括进程的创建、进程的调度、进程的消亡 2.进程相关命令: 1.top 动态查看当前系统中的所有进程信息&#xff08;根据CPU占用率排序&#xf…

PHY6222系统级SOC蓝牙芯片低功耗高性能蓝牙MESH组网智能家居

简介 PHY6222是一款支持BLE 5.2功能和IEEE 802.15.4通信协议的系统级芯片&#xff08;SoC&#xff09;&#xff0c;集成了超低功耗的高性能多模射频收发机&#xff0c;搭载32-bit ARM?Cortex?-M0处理器&#xff0c;提供64K retention SRAM、可选128K-8M Flash、96KB ROM以及2…

十、线性代数二-线性相关

目录 1、线性相关的概念&#xff1a; 2、线性相关的代数表示&#xff1a; 3、线性相关的判断方法&#xff1a; 理解&#xff1a;线性相关指的是 向量组&#xff08;α1&#xff0c;α2&#xff0c;α3&#xff0c;...&#xff09;的 秩是 小于 k 的元数的&#xff0c;即齐次…

第二节:Vben Admin 登录逻辑梳理和对接后端准备

系列文章目录 上一节&#xff1a;第一节&#xff1a;Vben Admin介绍和初次运行 文章目录 系列文章目录前言项目路径的概述一、登录逻辑梳理loginApi接口查看Mock 二、后端程序对接准备关闭Mock 总结 前言 第一节&#xff0c;我们已经配置了前端环境&#xff0c;运行起来了我们…

文献速递:深度学习--深度学习方法用于帕金森病的脑电图诊断

文献速递&#xff1a;深度学习–深度学习方法用于帕金森病的脑电图诊断 01 文献速递介绍 人类大脑在出生时含有最多的神经细胞&#xff0c;也称为神经元。这些神经细胞无法像我们身体的其他细胞那样自我修复。随着年龄的增长&#xff0c;神经元逐渐死亡&#xff0c;因此变得…

el-form 表单文本标签label增加tooltip提示图标

需求&#xff1a;在el-form表单中&#xff0c;el-form-item的文本标签处增加提示语&#xff1b; 标签&#xff1a;el-form、el-form-item、el-tooltip&#xff1b; 实现&#xff1a; <el-form-item prop"basicScore"><span slot"label"><…

nginx之状态页 日志分割 自定义图表 证书

5.1 网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状态 server{…

【Git】Git命令的学习与总结

本文实践于 Learn Git Branching 这个有趣的 Git 学习网站。在该网站&#xff0c;可以使用 show command 命令展示所有可用命令。你也可以直接访问网站的sandbox&#xff0c;自由发挥。 一、本地篇 基础篇 git commit git commit将暂存区&#xff08;staging area&#xff…

采访影视行业人“Sora入局,或将改变游戏规则?”

自OpenAI发布Sora已经过去了半个月&#xff0c;人们对于这个新兴的“文生视频”&#xff08;text-to-video&#xff09;大模型工具都已经有了初步的认识&#xff0c;经过半个月的沉淀&#xff0c;他们也陆续发布了一些更加令人震惊的demo&#xff0c;话不多说&#xff0c;我们先…

Bootstrap引入和使用

Bootstrap 基础用法 目录 Bootstrap 基础用法什么是Bootstrap&#xff1f;引入Bootstrap布局容器栅格系统表格样式表单样式text样式按钮样式图标 什么是Bootstrap&#xff1f; Bootstrap是一个开源的前端框架&#xff0c;用于对HTML和CSS代码进行封装&#xff0c;因此可以直接…

Springboot集成Druid实现监控功能

Druid是阿里巴巴开发的号称为监控而生的数据库连接池&#xff0c;在功能、性能、扩展性方面&#xff0c;都超过其他数据库连接池&#xff0c;包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource等等等&#xff0c;秒杀一切。Druid可以很好的监控DB池连接和SQL的执行情况&#…