当前位置: 首页 > news >正文

Spring Security Oauth2.0认证授权

  1. 基本概念

  • 认证: 用户认证就是判断一个用户的身份是否合法的过程 ,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。常见的用户身份认证方式有:用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。

  • 会话:用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保证在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。

  • 授权:授权是用户认证通过后根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问。授权可简单理解为Who对What(which)进行How操作,

  • Who,即主体( Subject), 主体一般是指用户,也可以是程序,需要访问系统中的资源。

  • What,即资源( Resource), 如系统菜单、页面、按钮、代码方法、系统商品信息、系统订单信息等。系统菜单、页面、按钮、代码方法都属于 系统功能资源,对于web系统每个功能资源通常对应一个URL ;系统商品信息系统订单信息都属于 实体资源(数据资源), 实体资源由资源类型和资源实例组成,比如商品信息为资源类型,商品编号为001的商品为资源实例。

  • How ,权限/许可( Permission), 规定了用户对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个代码方法的调用权限、编号为001的用户的修改权限等,通过权限可知用户对哪些资源都有哪些操作许可。

  • 授权的数据模型

资源和权限可以合并一起

  • RBAC

基于角色的访问控制 if (主体.hasRole()){}

基于资源的访问控制 if(主体.hasPermission()){}

  1. Spring Boot Security

对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源,通过Filter实现

2.1 结构原理

初始化Spring Security时,初始化一个类型为org.springframework.security.web.FilterChainProxy的过滤器,

外部的请求会经过此类。FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是Spring Security核心,并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给认证管理器(AuthenticationManager)决策管理器(AccessDecisionManager)进行处理

spring Security功能的实现主要是由一系列过滤器链相互配合完成。

2.2 认证过程

1. 用户提交用户名、密码被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。

2. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证

3. 认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除) Authentication 实例。

4. SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication ,通过

SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。

  • AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,

它的实现类为ProviderManager。

  • 而Spring Security支持多种认证方式,因此ProviderManager维护着一个List<AuthenticationProvider> 列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成。不同的认证方式使用不同的AuthenticationProvider。如使用用户名密码登录时,使用DaoAuthenticationProvide

  • DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。

2.3 密码处理

Spring Security提供了很多内置的PasswordEncoder,能够开箱即用,使用某种PasswordEncoder只需要进行如

下声明即可

常见的密码编码器有

NoOpPasswordEncoder、BCryptPasswordEncoder、Pbkdf2PasswordEncode、SCryptPasswordEncoder

2.4 授权过程

  • 已认证用户访问受保护的web资源将被SecurityFilterChain中的 FilterSecurityInterceptor 的子类拦截。

  • FilterSecurityInterceptor会从 SecurityMetadataSource 的子类DefaultFilterInvocationSecurityMetadataSource 获取要访问当前资源所需要的权限Collection<ConfigAttribute>

  • SecurityMetadataSource其实就是读取“安全拦截机制”

  • FilterSecurityInterceptor会调用 AccessDecisionManager 进行授权决策,若决策通过,则允许访问资源,否则将禁止访问。此处会从安全上下文中获取用户:Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 再进行比对和判断。

  • decide接口就是用来鉴定当前用户是否有访问对应受保护资源的权限。

  • authentication:要访问资源的访问者的身份

  • object:要访问的受保护资源,web请求对应FilterInvocation

  • confifigAttributes:是受保护资源的访问策略,通过SecurityMetadataSource获取。

Spring Security内置了三个基于投票的AccessDecisionManager实现类

AffirmativeBased 只要有一个赞成票,则表示同意用户访问

ConsensusBased:赞成票多余反对票,则表示同意用户访问

UnanimousBased:只要有一个反对票,则表示反对用户访问

spring security为防止CSRF(Cross-site request forgery跨站请求伪造)的发生,限制了除了get以外的大多数方法,

解决方法1:

屏蔽CSRF控制,即spring security不再限制CSRF。httpSecurity.csrf().disable()

解决方法2:

表单添加隐藏域: <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

2.5 实际应用

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。spring security提供会话管理,认证通过后将身份信息放入SecurityContextHolder上下文,SecurityContext与当前线程进行绑定,方便获取用户身份。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

2.5.1 会话控制

  • Spring Security会为每个登录成功的用户会新建一个Session

httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)

  • session超时、session失效后,通过Spring Security 设置跳转的路径。

httpSecurity.sessionManagement()

.expiredUrl("/login‐view?error=EXPIRED_SESSION")

.invalidSessionUrl("/login‐view?error=INVALID_SESSION");

  • session退出

httpSecurity.logout()

.logoutUrl("/logout")

.logoutSuccessUrl("/login‐view?logout")

.logoutSuccessHandler(logoutSuccessHandler)

.addLogoutHandler(logoutHandler)

.invalidateHttpSession(true)

定制的 LogoutSuccessHandler ,实现用户退出成功时的处理。如果指定了这个选项那么logoutSuccessUrl() 的设置被忽略;

添加一个 LogoutHandler ,用于实现用户退出时的清理工作.默认 SecurityContextLogoutHandler 会被添加为最后一个 LogoutHandler;

指定是否在退出时让 HttpSession 无效。 默认设置为 true

2.5.2 web授权

使用 http.authorizeRequests() 对web资源进行授权保护

httpSecurity

.authorizeRequests()

.antMatchers("/r/r1").hasAuthority("p1") (

.antMatchers("/r/r2").hasAuthority("p2")

.antMatchers("/r/r3").access("hasAuthority('p1') and hasAuthority('p2')")

.antMatchers("/r/**").authenticated()

.anyRequest().permitAll()

.and()

.formLogin()

  • 保护URL常用的方法有:

authenticated() 保护URL,需要用户登录

permitAll() 指定URL无需保护,一般应用与静态资源文件

hasRole(String role) 限制单个角色访问,角色将被增加 “ROLE_” .所以”ADMIN” 将和 “ROLE_ADMIN”进行比较.

hasAuthority(String authority) 限制单个权限访问

hasAnyRole(String… roles)允许多个角色访问.

hasAnyAuthority(String… authorities) 允许多个权限访问.

access(String attribute) 该方法使用 SpEL表达式, 所以可以创建复杂的限制.

hasIpAddress(String ipaddressExpression) 限制IP地址或子网

2.5.3.方法授权

以在任何 @Configuration 实例上使用 @EnableGlobalMethodSecurity 注释来启用基于注解的安全性。

@PreAuthorize,@PostAuthorize, @Secured三类注解作用域服务层方法上,限制访问的访问

例如:

  • 匿名访问

@Secured("IS_AUTHENTICATED_ANONYMOUSLY")

@PreAuthorize("isAnonymous()")

方法可匿名访问,底层使用WebExpressionVoter投票器

  • @PreAuthorize

@PreAuthorize("hasAuthority('p_transfer') and hasAuthority('p_read_account')")

同时拥有p_transfer和p_read_account权限才能访问,底层使用WebExpressionVoter投票器

另外,还有注解@PostAuthorize

  1. 分布式系统认证方案

软件的架构由单体结构演变为分布式架构,具有分布式架构的系统叫分布式系统,分布式系统的运行通常依赖网络,它将单体结构的系统分为若干服务,服务之间通过网络交互来完成用户的业务处理,当前流行的微服务架构就是分布式系统架构。

3.1 分布式认证需求

分布式系统的每个服务都会有认证、授权的需求,考虑分布式系统共享性的特点,需要由独立的认证服务处理系统认证授权的请求;考虑分布式系统开放性的特点,不仅对系统内部服务提供认证,对第三方系统也要提供认证。分布式认证的需求总结如下:

统一认证授权

提供独立的认证服务,统一处理认证授权。无论是不同类型的用户,还是不同种类的客户端(web端,H5、APP),均采用一致的认证、权限、会话机制,实现统一认证授权。要实现统一则认证方式必须可扩展,支持各种认证需求,比如:用户名密码认证、短信验证码、二维码、人脸识别等认证方式,并可以非常灵活的切换。

应用接入认证

应提供扩展和开放能力,提供安全的系统对接机制,并可开放部分API给接入第三方使用,一方应用(内部系统服务)和三方应用(第三方应用)均采用统一机制接入。

3.2 选型分析

3.2.1 基于Session认证

每个应用服务都需要在session中存储用户身份信息,通常的做法有下面几种:

Session复制:多台应用服务器之间同步session,使session保持一致,对外透明。

Session黏贴:当用户访问集群中某台服务器后,强制指定后续所有请求均落到此机器上。

Session集中存储:将Session存入分布式缓存中,所有服务器应用实例统一从分布式缓存中存取Session。

基于session认证的认证方式,可以更好的在服务端对会话进行控制,且安全性较高。但是,session机制方式基于cookie,在复杂多样的移动客户端上不能有效的使用,并且无法跨域,另外随着系统的扩展需提高session的复制、黏贴及存储的容错性。

3.2.2 基于Token认证

基于token的认证方式,服务端不用存储认证数据,易维护扩展性强, 客户端可以把token 存在任意地方,并且可以实现web和app统一认证机制。其缺点也很明显,token由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token的签名验签操作也会给cpu带来额外的处理负担。

3.2.3 技术方案

根据 选型分析,采用token认证,它的优点是:

  1. 适合统一认证的机制,客户端、一方应用、三方应用都遵循一致的认证机制。

  1. token认证方式对第三方应用接入更适合,因为它更开放,可使用当前有流行的开放协议Oauth2.0、JWT等。

  1. 一般情况服务端无需存储会话信息,减轻了服务端的压力。

3.3 Oauth2.0

OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。例如,第三方登录,用户 授权 电商网站 访问 用户存储在微信平台的用户信息

OAauth2.0包括以下角色:

  1. 客户端

本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如:Android客户端、Web客户端(浏览器端)、微信客户端等。

  1. 资源拥有者

通常为用户,也可以是应用程序,即该资源的拥有者。

  1. 资源服务器

存储资源的服务器,例如微信平台用户信息资源。

服务提供商会给准入的接入方一个身份,用于接入时的凭据:

client_id:客户端标识

client_secret:客户端秘钥

  1. 授权服务器(也称认证服务器)

用于服务提供商对资源拥有的身份进行认证、对访问资源进行授权,认证成功后会给客户端发放令牌,作为客户端访问资源服务器的凭据。例如:微信认证服务器。

授权服务器对OAuth2.0中的两个角色进行认证授权,分别是资源拥有者客户端

  1. Spring Cloud Security OAuth2

Spring-Security-OAuth2是对OAuth2的一种实现,并且跟Spring Security相辅相成,与SpringCloud体系的集成也非常便利。其服务实现包括两个服务:

  • 认证授权服务 (Authorization Server)

应包含对接入端以及登入用户的合法性进行验证并颁发token等功能,对令牌的请求端点由 Spring MVC 控制器进行实现,下面是配置一个认证服务必须要实现的endpoints:

AuthorizationEndpoint 服务于认证请求。默认 URL:

/oauth/authorize 。

TokenEndpoint 服务于访问令牌的请求。默认 URL:

/oauth/token 。

  • 资源服务 (Resource Server)

应包含对资源的保护功能,对非法请求进行拦截,对请求中token进行解析鉴权等,下面的过滤器用于实现 OAuth 2.0 资源服务:

OAuth2AuthenticationProcessingFilter用来对请求给出的身份令牌解析鉴权。

4.1 授权服务器配置

可以使用

@Configuration

@EnableAuthorizationServer

注解并继承AuthorizationServerConfifigurerAdapter来配置OAuth2.0 授权服务器。

AuthorizationServerConfifigurerAdapter要求配置

ClientDetailsServiceConfifigurer:用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化

AuthorizationServerEndpointsConfifigurer:用来配置令牌(token)的访问端点和令牌服务(tokenservices)。

AuthorizationServerSecurityConfifigurer:用来配置令牌访问端点的安全约束

4.1.1 客户端详情

ClientDetailsServiceConfifigurer能够使用内存或者JDBC来实现客户端详情,ClientDetailsService负责查找ClientDetails,而ClientDetails有几个重要的属性

客户端详情(Client Details)能够在应用程序运行的时候进行更新,可以通过访问底层的存储服务(例如将客户端详情存储在一个关系数据库的表中,就可以使用 JdbcClientDetailsService)或者通过实现

ClientRegistrationService接口(同时你也可以实现 ClientDetailsService 接口)来管理。

此次客户端详情读取数据库的配置:

4.1.2 令牌管理服务

AuthorizationServerTokenServices 接口定义了一些操作可以对令牌进行一些必要的管理,这个接口的实现,则需要继承 DefaultTokenServices,里面包含了一些有用实现,你可以使用它来修改令牌的格式和令牌的存储,其持久化令牌委托一个 TokenStore 接口来实现,TokenStore 这个接口有一个默认的实现,它就是 InMemoryTokenStore。

  • InMemoryTokenStore:

这个版本的实现是被默认采用的,它可以完美的工作在单服务器上(即访问并发量压力不大的情况下,并且它在失败的时候不会进行备份),大多数的项目都可以使用这个版本的实现来进行尝试,可以在开发的时候使用它来进行管理,因为不会被保存到磁盘中,更易于调试。

  • JdbcTokenStore:

这是一个基于JDBC的实现版本,令牌会被保存进关系型数据库。使用这个版本的实现时,你可以在不同的服务器之间共享令牌信息,使用这个版本的时候需要把"spring-jdbc"这个依赖加入到classpath。

  • JwtTokenStore

这个版本的全称是 JSON Web Token(JWT),它可以把令牌相关的数据进行编码(因此对于后端服务来说,它不需要进行存储,这将是一个重大优势),但是它有一个缺点,那就是撤销一个已经授权令牌将会非常困难,所以它通常用来处理一个生命周期较短的令牌以及撤销刷新令牌(refresh_token)。另外一个缺点就是这个令牌占用的空间会比较大,如果你加入了比较多用户凭证信息。JwtTokenStore 不会保存任何数据,但是它在转换令牌值以及授权信息方面与 DefaultTokenServices 所扮演的角色是一样的。

4.1.3 令牌访问端点

4.1.3.1 认证管理器

AuthorizationServerEndpointsConfifigurer通过设定以下属性决定支持的授权类型(Grant Types):

  • authenticationManager

认证管理器,选择了资源所有者密码(password)授权类型的时候,请设置这个属性注入一个 AuthenticationManager 对象。

  • userDetailsService

设置了这个属性,需要有一个 UserDetailsService 接口的实现

  • authorizationCodeServices:

用来设置授权码服务(即 AuthorizationCodeServices 的实例对象),主要用于 "authorization_code" 授权码类型模式。

  • implicitGrantServic

这个属性用于设置隐式授权模式,用来管理隐式授权模式的状态。

  • tokenGranter:

授权将会交由自己来完全掌控,并且会忽略掉上面的这几个属性,这个属性一般是用作拓展用途

4.1.3.2 令牌访问点

框架的默认URL访问链接如下列表

/oauth/authorize:授权端点。

/oauth/token:令牌端点。

/oauth/confifirm_access:用户确认授权提交端点。

/oauth/error:授权服务错误信息端点。

/oauth/check_token:用于资源服务访问的令牌解析端点。

/oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话。

AuthorizationServerEndpointsConfifigurer 这个配置对象有一个叫做 pathMapping() 的方法用来配置端点URL链接,它有两个参数:

第一个参数:String 类型的,这个端点URL的默认链接。

第二个参数:String 类型的,你要进行替代的URL链接。

4.1.4 令牌访问端点安全约束

AuthorizationServerSecurityConfigurer: :用来配置令牌端点(Token Endpoint)的安全约束

4.1.5 WEB安全配置

4.1.6 授权类型

4.1.6.1授权码模式

  • 资源拥有者打开客户端,客户端要求资源拥有者给予授权,它将浏览器被重定向到授权服务器,重定向时会附加客户端的身份信息

/uaa/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com

  • 浏览器出现向授权服务器授权页面,之后用户同意授权

  • 授权服务器将授权码(AuthorizationCode)经浏览器发送给client

  • 客户端拿着授权码向授权服务器索要访问access_token

/uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=authorization_code&code=5PgfcD&redirect_uri=http://www.baidu.com

  • 授权服务器返回令牌(access_token)

参数列表如下

client_id:客户端准入标识。

response_type:授权码模式固定为code。

scope:客户端权限。

client_secret:客户端秘钥。

grant_type:授权类型,填写authorization_code,表示授权码模式

code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。

redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。

4.1.6.2 简化模式

  • 资源拥有者打开客户端,客户端要求资源拥有者给予授权,它将浏览器被重定向到授权服务器,重定向时会附加客户端的身份信息

/uaa/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com

  • 浏览器出现向授权服务器授权页面,之后用户同意授权

  • 授权服务器将授权码将令牌(access_token)以Hash的形式存放在重定向uri的fargment中发送给浏览器。fragment 主要是用来标识 URI 所标识资源里的某个资源,在 URI 的末尾通过 (#)作为 fragment 的开头,其中 # 不属于 fragment 的值。

4.1.6.3 密码模式

  • 资源拥有者将用户名、密码发送给客户端

  • 客户端拿着资源拥有者的用户名、密码向授权服务器请求令牌(access_token)

/uaa/oauth/token?

client_id=c1&client_secret=secret&grant_type=password&username=shangsan&password=123

  • 授权服务器将令牌(access_token)发送给client

4.1.6.4 客户端模式

  • 客户端向授权服务器发送自己的身份信息,并请求令牌(access_token)

  • 确认客户端身份无误后,将令牌(access_token)发送给client

/uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials

4.2资源服务器配置

@Configuration

@EnableResourceServer

public class ResouceServerConfig extends ResourceServerConfigurerAdapter

@EnableResourceServer 注解自动增加了一个类型为 OAuth2AuthenticationProcessingFilter 的过滤器链

  • ResourceServerSecurityConfifigurer中主要包括:

tokenServices:ResourceServerTokenServices 类的实例,用来实现令牌服务。

tokenStore:TokenStore类的实例,指定令牌如何访问,与tokenServices配置可选

resourceId:这个资源服务的ID,这个属性是可选的,但是推荐设置并在授权服务中进行验证。

其他的拓展属性例如 tokenExtractor 令牌提取器用来提取请求中的令牌。

  • HttpSecurity配置这个与Spring Security类似:

请求匹配器,用来设置需要进行保护的资源路径,默认的情况下是保护资源服务的全部路径。

通过http.authorizeRequests()来设置受保护资源的访问规则

其他的自定义权限保护规则通过 HttpSecurity 来进行配置。

RemoteTokenServices 资源服务器通过 HTTP 请求来解码令牌,每次都请求授权服务器端点 /oauth/check_token

此处使用JWT校验令牌

配置安全拦截机制

@EnableResourceServer 注解自动增加了一个类型为 OAuth2AuthenticationProcessingFilter 的过滤器链,此过滤器作用,主要是用来解析网关传过来的用户信息字符串,并存入安全上下文中

4.3 网关

网关整合 OAuth2.0作为OAuth2.0的资源服务器角色,实现接入客户端权限拦截、令牌解析并转发当前登录用户信息(jsonToken)给微服务

public class AuthFilter extends ZuulFilter

校验客户端token,验证接入客户端权限,并解析后明文token,转发请求到微服务

相关文章:

Spring Security Oauth2.0认证授权

基本概念认证: 用户认证就是判断一个用户的身份是否合法的过程 &#xff0c;用户去访问系统资源时系统要求验证用户的身份信息&#xff0c;身份合法方可继续访问&#xff0c;不合法则拒绝访问。常见的用户身份认证方式有:用户名密码登录&#xff0c;二维码登录&#xff0c;手机…...

安卓小游戏:贪吃蛇

安卓小游戏&#xff1a;贪吃蛇 前言 这个是通过自定义View实现小游戏的第二篇&#xff0c;实际上第一篇做起来麻烦点&#xff0c;后面的基本就是照葫芦画瓢了&#xff0c;只要设计下游戏逻辑就行了&#xff0c;技术上不难&#xff0c;想法比较重要。 需求 贪吃蛇&#xff0…...

CUDA中的图内存节点

CUDA中的图内存节点 文章目录CUDA中的图内存节点1. 简介2. 支持的架构和版本3. API基础知识3.1. 图节点 APIs3.2. 流捕获3.3. 在分配图之外访问和释放图内存3.4. cudaGraphInstantiateFlagAutoFreeOnLaunch4. 优化内存复用4.1. 解决图中的重用问题4.2. 物理内存管理和共享5. 性…...

你真的看好低代码开发吗?

低代码开发前景如何&#xff0c;大家真的看好低代码开发吗&#xff1f;之前有过很多关于低代码的内容&#xff0c;这篇就来梳理下国内外低代码开发平台发展现状及前景。 01、国外低代码开发平台现状 2014年&#xff0c;研究机构Forrester Research发表的报告中提到“面向客户…...

一篇带你MySQL运维

1. 日志 1.1 错误日志 错误日志是 MySQL 中 重要的日志之一&#xff0c;它记录了当 mysqld启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 该日志是默认开启的&…...

《嵌入式 – GD32开发实战指南》第22章 SPI

开发环境&#xff1a; MDK&#xff1a;Keil 5.30 开发板&#xff1a;GD32F207I-EVAL MCU&#xff1a;GD32F207IK 22.1 SPI简介 SPI&#xff0c;是Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的…...

一个优质软件测试工程师的简历应该有的样子(答应我一定要收藏起来)

个人简历 基本信息 姓 名&#xff1a;xxx 性 别&#xff1a; 女 年 龄&#xff1a;24 现住 地址&#xff1a; 深圳 测试 经验&#xff1a;3年 学 历&#xff1a;本科 联系 电话&#xff1a;18xxxxxxxx 邮 箱&#xff1a;xxxxl163.com 求职意向 应聘岗位&#xff1a;软件…...

C++ 浅谈之 STL Deque

C 浅谈之 STL Deque HELLO&#xff0c;各位博友好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 这里是 C 浅谈系列&#xff0c;收录在专栏 C 语言中 &#x1f61c;&#x1f61c;&#x1f61c; 本系列阿呆将记录一些 C 语言重要的语法特性 &#x1f3c3;&a…...

Koa2-项目中的基本应用

文章目录安装配置koa2配置nodemon,热更新我们的项目中间件什么是中间件&#x1f47b;洋葱模型路由中间件连接数据库 - mysql后端允许跨域处理请求getpostputdelete后续会继续更新安装配置koa2 &#x1f47b;安装 koa2 npm i koa2 -s&#x1f47b;在package.json 配置,当然是在…...

Flask入门(2):配置

目录2.Flask配置2.1 直接写入主脚本2.2 系统环境变量2.3 单独的配置文件2.4 多个配置类2.5 Flask内置配置2.Flask配置 我们都知道&#xff0c;Flask应用程序肯定是需要各种各样的配置。来满足我们不同的需求的&#xff0c;这样可以使我们的应用程序更加灵活。比如可以根据需要…...

Linux--fork

一、fork入门知识 fork&#xff08;&#xff09;函数通过系统调用创建一个与原来进程几乎完全相同的进程&#xff0c;也就是两个进程可以做完全相同的事&#xff0c;但如果初始参数或者传入的变量不同&#xff0c;两个进程也可以做不同的事。可以简单地说fork()的作用就是创建一…...

计算机组成原理(一)

1.了解计算机硬件的发展和软件的发展历程&#xff1b; 硬件&#xff1a;   电子管时代&#xff08;1946-1959&#xff09;&#xff1a;电子管、声汞延迟线、磁鼓   晶体管时代&#xff08;1959-1964&#xff09;&#xff1a;晶体管、磁芯   中、小规模集成电路时代&#…...

【SpringBoot】实现Async异步任务

1. 环境准备 在 Spring Boot 入口类上配置 EnableAsync 注解开启异步处理。 创建任务抽象类 AbstractTask&#xff0c;并分别配置三个任务方法 doTaskOne()&#xff0c;doTaskTwo()&#xff0c;doTaskThree()。 public abstract class AbstractTask {private static Random r…...

Node =>Express学习

1.Express 能做什么 能快速构建web网站的服务器 或 Api接口的服务期 Web网站服务器&#xff0c;专门对外提供Web网页资源的服务器Api接口服务器&#xff1a;专门对外提供API接口的服务器 2.安装 在项目所处的目录中&#xff0c;运行以下命令&#xff0c;简装到项目中了 npm …...

QT基础入门【布局篇】消除控件之间的间隔

一、相关参数 layoutLeftMargin: layout内的布局距离边框左端的距离。 layoutTopMargin: layout内的布局距离边框顶端的距离。 layoutRightMargin: layout内的布局距离边框右端的距离。 layoutBottomMargin: layout内的布局距离边框底端的距离。 layoutHorizontalSpacing: layo…...

vue脚手架 element-ui spring boot 实现图片上传阿里云 并保存到数据库

一.阿里云 注册登陆就不讲了&#xff0c;登陆进去后如下操作 1. 进入对象存储OSS 创建一个新的Bucket 随后点击新建的bucket 2.去访问RAM 前往RAM控制台 3.去创建用户 4.创建密匙 5.随后返回RAM控制台 给用户增加权限&#xff0c;文件上传所需权限&#xff0c;需要带含有…...

【FPGA】Verilog:组合电路 | 3—8译码器 | 编码器 | 74LS148

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;编码/译码器的应用 ​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器&…...

GLP-1类药物研发进展-销售数据-上市药品前景分析

据一项2021 年的报告发现&#xff0c;当 GLP-1 类似物用于治疗 2 型糖尿病时&#xff0c;全因死亡率降低了 12%&#xff0c;它们不仅降糖效果显著&#xff0c;同时还兼具减重、降压、改善血脂谱等作用。近几年&#xff0c;随着GLP-1R激动剂类药物市场规模不断增长&#xff0c;美…...

C++远程监控系统接收端- RevPlayMDIChildWnd.cpp

void CRevPlayWnd::InitMultiSock() { int RevBuf; int status; BOOL bFlag; CString ErrMsg; SOCKADDR_IN stLocalAddr; SOCKADDR_IN stDestAddr; SOCKET hNewSock; int RevLensizeof(RevBuf); //创建一个IP组播套接字 MultiSock W…...

QT之OpenGL深度测试

QT之OpenGL深度测试1. 深度测试概述1. 1 提前深度测试1.2 深度测试相关函数2. 深度测试精度2.1 深度冲突3. Demo4. 参考1. 深度测试概述 在OpenGL中深度测试(Depth Testing)是关闭的&#xff0c;此时在渲染图形时会产生一种现象后渲染的会把最先渲染的遮挡住。而在启用深度测试…...

用LCR测试仪测试无线充电系统中的线圈

宽阻抗范围用来表征电感和质量因数– 高精度 DCR 测量– 制造环节快速测量– 大量夹具可供选择智能终端上不断增加新功能&#xff0c;电池寿命成为用户最头痛的问题之一。相比便携式电源和电缆供电而言&#xff0c;无线充电技术因其方便性和多功能性获得了很大的关注&#xff0…...

华为、南卡和漫步者蓝牙耳机怎么选?国产高性价比蓝牙耳机推荐

随着蓝牙耳机的快速发展&#xff0c;现如今使用蓝牙耳机的人也越来越多。其中&#xff0c;日益增多的国产蓝牙耳机品牌也逐渐被大众认识、认可。目前一些热销的国产蓝牙耳机&#xff0c;如华为、南卡和漫步者等都是大家比较熟知的品牌。那么&#xff0c;这三个品牌哪个性价比高…...

MySQl学习(从入门到精通12)

MySQl学习&#xff08;从入门到精通12&#xff09;第 15 章_存储过程与函数1. 存储过程概述1. 1 理解1. 2 分类2. 创建存储过程2. 1 语法分析2. 2 代码举例3. 调用存储过程3. 1 调用格式3. 2 代码举例3. 3 如何调试4. 存储函数的使用4. 1 语法分析4. 2 调用存储函数4. 3 代码举…...

08讲 | 基于STM32单片机NBIOT定位实战项目

前言 绘制基于 STM32 单片机的 NBIOT 实战开发板。 文章目录前言一、原理图1、绘制1&#xff09;电源供电a、USB 转 TTL 电路b、锂电池充电管理电路c、3.3V电压转换电路d、一键开关机电路2&#xff09;单片机最小系统3&#xff09;ADC电压转换电路4&#xff09;NBIOT 模组串口电…...

提取接近竖直物体(粗定位)

由于项目的需要提取图像之中的一个接近于竖直的物体&#xff0c;一般的方法是进行图像分割&#xff0c;分割方式使用什么OTSU方式以及hsv方法等等。但是项目中使用的相机是黑白相机&#xff0c;会受到一定的限制。因此想到的是使用线条提取方式。线条提取方式之中最好的方法是使…...

程序环境和预处理

目录一、程序的翻译环境和执行环境二、编译链接2.1 翻译环境2.2 编译2.2.1 预处理2.2.2 编译2.2.3 汇编2.3 链接2.4 结果三、运行环境四、预处理详解4.1 #define4.1.1 #define定义标识符4.1.2 #define定义宏4.1.3 #define 替换规则4.1.4 #和##4.1.5 带副作用的宏参数4.1.6 宏和…...

财报解读:业务复苏迹象明显,中国中免能否重写增长神话?

2月3日&#xff0c;中国中免披露2022年度业绩快报&#xff0c;2022年总营收为544.63亿元&#xff0c;同比下降19.52%&#xff1b;实现归属于上市公司股东的净利润50.25亿元&#xff0c;同比下降47.95%。来源&#xff1a;中国中免2022年度业绩快报业绩近乎腰斩&#xff0c;但从长…...

macOS中虚拟机桥接模式分配静态ip

1.首先使用dhclient命令&#xff0c;在局域网中分配一个C类地址。 2.获得地址后&#xff0c;输入ifconfig&#xff0c;查看分配的地址。 3.然后编辑vi /etc/sysconfig/network-scripts/ifcfg-en***文件 在该配置文件中编辑&#xff0c;设置ONBOOTyes&#xff0c;而后添加静态配…...

prometheus increase函数统计得到小数

今天发现prometheus的increase函数得到了小数&#xff0c;研究一下源码&#xff0c;以下是rate/increase/delta 对应的计算函数https://github.com/prometheus/prometheus/blob/d77b56e88e3d554a499e22d2073812b59191256c/promql/functions.go#L55// extrapolatedRate is a uti…...

C++学习记录——유 类和对象(3)

文章目录1、赋值运算符重载1、运算符重载1、理解2、运算符重载实例2、赋值运算符重载2、日期类的实现1、加减函数1、加函数2、减函数2、前/后置--重载3.两个日期相减其他1、流插入2、流提取日期类的整体实现代码: https://gitee.com/kongqizyd/start-some-c-codes-for-learning…...

wordpress是哪个公司的/seo工资一般多少

2016年4月11日作业 一、法律法规和标准规范1、中国标准划分为哪四个层次&#xff1f;要求最低的是哪个&#xff1f;国家标准、行业标准、地方标准和企业标准&#xff0c;其中要求最低的是国家标准。2、国家标准的制订程序包括哪些&#xff1f;前期准备、立项、起草、征求意见、…...

如何用图片做网站背景/百度投流运营

java中int和Integer的区别 一看就懂int 是基本类型&#xff0c;直接存数值integer是对象&#xff0c;用一个引用指向这个对象1.Java 中的数据类型分为基本数据类型和复杂数据类型int 是前者>>integer 是后者(也就是一个类)Integer 是对象类型 int是原始类型 适用场合有很…...

网站建设网站建/百度竞价推广代运营公司

背景描述 EasyNVR的使用者应该都是清楚的了解到&#xff0c;EasyNVR一个强大的功能就是可以进行全平台的无插件直播。主要原因在于rtsp协议的视频流&#xff08;默认是需要插件才可以播放的&#xff09;经由EasyNVR处理可以满足无插件的全平台直播。 经由EasyNVR处理会获取到RT…...

专业建站开发/网络营销培训课程

注&#xff1a;以下内容适用于WPF、C#编码。 最近对异步编程产生了较大的兴趣&#xff0c;所以写出来和感兴趣的朋友一起分享&#xff01; 1、关于Dispatcher 调度类&#xff1a; 提供用于管理线程的工作项队列的服务。 通常&#xff0c;WPF 应用程序从两个线程开始&#…...

wordpress 客户端使用/百度ai营销中国行

38-博客网站数据库-博文分类信息数据操作(二) 项目描述 当今网上微博、博客发布信息已经成为主要的信息发布、传播的系统&#xff0c;如何对这些数据进行管理&#xff0c;本项目主要是对博客网站中的博文分类信息表、博文信息表进行操作。 博客网站的数据库操作要求如下&…...

南通单位网站建设/活动推广文案

在没接触Linux之前&#xff0c;一直都是用的C和C来写程序&#xff0c;直到现在才发现脚本语言也是那么的有魅力&#xff0c;shell、awk、sed、perl、python等都是那么的好用&#xff0c;虽然刚接触python编程语言没几天&#xff0c;但是已经深深的被其所吸引&#xff0c;今后我…...