Spring Security 身份验证的基本类/架构
目录
1、SecurityContextHolder 核心类
2、SecurityContext 接口
3、Authentication 用户认证信息接口
4、GrantedAuthority 拥有权限接口
5、AuthenticationManager 身份认证管理器接口
6、ProviderManager 身份认证管理器的实现
7、AuthenticationProvider 特定类型的身份验证接口
8、AuthenticationEntryPoint 身份验证方案接口
9、AbstractAuthenticationProcessingFilter 用户凭据验证过滤器
// Spring Security 基于 Servlet 的身份验证和身份验证的基本构件
- SecurityContextHolder(类)——用来存储身份验证详细信息。//验证流程核心类
- SecurityContext(接口)——从SecurityContextHolder 中获取,包含当前认证用户的身份验证信息。
- Authentication(接口) ——该对象可以通过 AuthenticationManager 进行赋值,作为用户身份验证的凭据,然后通过 SecurityContext 获取 Authentication 的详细信息。
- GrantedAuthority(接口)——用于对用户的授权。
- AuthenticationManager(接口)——用于定义 Spring Security 过滤器如何执行身份验证的API。
- ProviderManager(类)——AuthenticationManager 最常见的实现。//常规实现
- AuthenticationProvider(接口)——提供给ProviderManager,用于执行特定类型的身份验证。//身份验证的具体细节由xxxProvider提供
- AuthenticationEntryPoint(接口)——用于从客户端请求用户凭据(例如,重定向到登录页面,发送WWW-Authenticate响应等)
- AbstractAuthenticationProcessingFilter(抽象类)——用于身份验证的基本过滤器。通过该类可以很好地了解身份验证流程及各个部分如何协同工作的过程。//所有身份验证的过滤器都会实现该类
1、SecurityContextHolder 核心类
SecurityContextHolder 类是 Spring Security 身份验证模型的核心, 在该类中包含了存储用户认证信息的上下文 SecurityContext。
下边是一个对象之间的包含关系图,它很重要,对于理解 Spring Security 中的对象关系非常有用:
SecurityContextHolder 用来存储身份验证详细信息。Spring Security 并不关心SecurityContextHolder 是如何填充的。如果其中包含值,则使用该值作为当前通过认证的用户信息。//只要SecurityContextHolder有值就会被使用
所以,指示用户已被认证的最简单方法就是直接设置 SecurityContextHolder:
SecurityContext context = SecurityContextHolder.createEmptyContext(); //1-创建Authentication -> Token接口
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER");
//2-设置用户信息
context.setAuthentication(authentication);SecurityContextHolder.setContext(context);
使用 TestingAuthenticationToken,是因为它非常简单。也可以使用 UsernamePasswordAuthenticationToken(UserDetails、密码、权限)等。
// 定义一个Authentication -> 放入SecurityContext -> 放入 SecurityContextHolder
在 SecurityContextHolder 上设置完 SecurityContext。Spring Security 会使用此信息进行授权。如果要获取已验证用户的有关信息,可以通过SecurityContextHolder获得:
//1-获取Security上下文
SecurityContext context = SecurityContextHolder.getContext();//2-获取用户通过身份验证的对象
Authentication authentication = context.getAuthentication();//-通过Authentication获取用户名称(密码方式)
String username = authentication.getName();
//-通过Authentication被认证用户的身份信息。
Object principal = authentication.getPrincipal();
//-通过Authentication用户权限信息
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
默认情况下,SecurityContextHolder 使用 ThreadLocal 来存储 SecurityContext,这意味着 SecurityContext 对于同一线程中的方法总是可用的,并不需要把 SecurityContext 作为参数显式地传递给这些方法。//SecurityContext 属于线程私有,如果我们不想显示传参,也可以这样用
//包含SecurityContext的成员变量private static SecurityContextHolderStrategy strategy; //初始化方法private static void initialize() {//1-如果没有指定mode,使用MODE_THREADLOCALif (!StringUtils.hasText(strategyName)) { strategyName = "MODE_THREADLOCAL";}if (strategyName.equals("MODE_THREADLOCAL")) {//2-默认策略strategy = new ThreadLocalSecurityContextHolderStrategy(); } else if (strategyName.equals("MODE_INHERITABLETHREADLOCAL")) {strategy = new InheritableThreadLocalSecurityContextHolderStrategy();} else if (strategyName.equals("MODE_GLOBAL")) {strategy = new GlobalSecurityContextHolderStrategy();} else {try {Class<?> clazz = Class.forName(strategyName);Constructor<?> customStrategy = clazz.getConstructor();strategy = (SecurityContextHolderStrategy)customStrategy.newInstance();} catch (Exception var2) {ReflectionUtils.handleReflectionException(var2);}}++initializeCount;}// MODE_THREADLOCAL策略final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {// 使用ThreadLocal保存SecurityContextprivate static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal();ThreadLocalSecurityContextHolderStrategy() {}//省略...}
因为使用了 ThreadLocal 存储值,如果处理完当前用户请求后需要清除线程中的ThreadLocal,避免内存泄漏。Spring Security 的FilterChainProxy会确保SecurityContext总是被清除。//FilterChainProxy是一个过滤器链的总代理,在总体架构那篇文章中提到过
//在FilterChainProxy中的doFilter方法中清除public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;if (!clearContext) {this.doFilterInternal(request, response, chain);} else {try {request.setAttribute(FILTER_APPLIED, Boolean.TRUE);this.doFilterInternal(request, response, chain);} catch (RequestRejectedException var9) {this.requestRejectedHandler.handle((HttpServletRequest)request, (HttpServletResponse)response, var9);} finally {//处理完一个用户请求时,SecurityContext在这里被清除SecurityContextHolder.clearContext(); request.removeAttribute(FILTER_APPLIED);}}}
2、SecurityContext 接口
SecurityContext 从 SecurityContextHolder 中获取。SecurityContext 包含一个 Authentication 对象。
// SecurityContext接口
public interface SecurityContext extends Serializable {//接口很简单,只包含对Authentication的get和set方法Authentication getAuthentication();void setAuthentication(Authentication var1);
}
SecurityContext 的实现类 SecurityContextImpl 也很简单,也就是对 Authentication 对象 get 和 set 方法的实现,所以重点还是 Authentication 对象。
3、Authentication 用户认证信息接口
在 Spring Security 中,Authentication 接口有两个主要用途:
- 作为 AuthenticationManager 对象 authenticate方法的入参,用于对用户进行身份验证。在此场景中,isAuthenticated() 返回 false。
- 获取已经过身份验证的用户信息,可以从 SecurityContext 中获取当前的用户信息。
一旦请求通过了AuthenticationManager#authenticate,Authentication 通常会存储在线程本地的 SecurityContext 中,由 SecurityContextHolder 进行管理。//Authentication->SecurityContext
注意,除非 Authentication 将 isAuthenticated 属性设置为 true,否则安全拦截器仍然会对其进行身份验证。
Authentication 接口详情://每个方法的注释都值得好好去读
public interface Authentication extends Principal, Serializable {//1-权限:由AuthenticationManager设置,用于指示已授予主体的权限。认证后不能为空(即无权限)Collection<? extends GrantedAuthority> getAuthorities();//2-密码:证明委托人正确的凭据。通常是密码Object getCredentials();//3-用户详情:存储有关身份验证请求的其他详细信息。如IP地址,证书序列号等Object getDetails();//4-用户名:被认证主体的身份。通常是用户名,许多身份验证提供程序将创建UserDetails对象作为主体Object getPrincipal();//用于指示AbstractSecurityInterceptor是否应该向AuthenticationManager提供身份验证令牌。//如果令牌已经过身份验证,并且AbstractSecurityInterceptor不需要再次向AuthenticationManager提供令牌以进行重新身份验证,则为true。boolean isAuthenticated();//如果令牌应该被信任(这可能导致异常),则为true;如果令牌不应该被信任,则为falsevoid setAuthenticated(boolean var1) throws IllegalArgumentException;
}
所以,综合上述,Authentication 包含三方面信息://总结起来就是:用户信息+权限
- Principal:用户主体信息,该信息通常是 UserDetails 的一个实例。
- Credentials:认证凭据,通常是密码。在许多情况下,用户通过身份验证后会被ProviderManager清除该属性,以确保凭据不会泄露。
- Authorities:用户权限,由 GrantedAuthority 进行授予。
4、GrantedAuthority 拥有权限接口
表示授予身份验证对象的权限。该接口的内容提供给授权管理器AuthorizationManager使用,以确定身份验证是否有权访问特定对象。//保存的是用户角色
//GrantedAuthority接口
public interface GrantedAuthority extends Serializable {String getAuthority(); //返回的是一个字符串 String role
}
// 所以,GrantedAuthority,这个玩意是用来授权的,存储已认证用户具备的访问权限。
通过 Authentication.getAuthorities() 方法可以获取 GrantedAuthority 的实例。此方法提供了 GrantedAuthority 对象的集合。毫无疑问,GrantedAuthority 是授予用户的权限。这些权限通常是“角色”信息,例如 ROLE_ADMINISTRATOR 或 ROLE_HR_SUPERVISOR。这些角色将配置给 Web 授权、方法授权和域对象授权使用。当使用基于用户名/密码的身份验证时,GrantedAuthority 实例通常由 UserDetailsService 加载。
通常,GrantedAuthority 对象是应用程序范围的权限。它们并不特定于给定的域对象。因此,不太可能使用 GrantedAuthority 来表示一个对象的具体权限,因为如果有数千个这样的权限,将很快耗尽内存(或者,会导致应用程序花费很长时间来进行验证)。// 其意思是说,GrantedAuthority 中的权限是一类权限(角色),而不是某个具体的功能,比如管理员权限能操作所有模块,而所有模块的功能汇聚在一起可能有好几百个。
5、AuthenticationManager 身份认证管理器接口
AuthenticationManager 定义 Spring Security 的过滤器如何执行身份验证的 API。用于处理身份验证请求。
public interface AuthenticationManager {//尝试对传递的身份验证对象进行身份验证,//如果成功,则返回一个完全填充的身份验证对象(包括授予的权限)。Authentication authenticate(Authentication var1) throws AuthenticationException;
}
Spring Security 的 Filters 实例会调用 AuthenticationManager 获取在 SecurityContextHolder上设置的 Authentication 对象进行身份验证。
如果直接设置 SecurityContextHolder,就不需要使用 AuthenticationManager。//直接填充身份信息,跳过认证步骤,由此可以见所有的认证流程也只是去SecurityContextHolder中设置一个Authentication而已
AuthenticationManager 可以有很多种实现,其中最常见的实现是 ProviderManager。
6、ProviderManager 身份认证管理器的实现
ProviderManager 是 AuthenticationManager 最常用的实现。ProviderManager 对用户的认证委托给一个 AuthenticationProvider 实例的列表。
//具体进行认证操作的实例列表
private List<AuthenticationProvider> providers;
每个 AuthenticationProvider 都有机会表明身份验证应该是成功的、失败的,或者表明它不能做出决定,并允许下游的 AuthenticationProvider 做出决定。
如果配置的 AuthenticationProvider 实例都不能进行身份验证,则身份验证失败并产生一个ProviderNotFoundException,这是一个特殊的 AuthenticationException,表明 ProviderManager 没有配置支持此 Authentication 对象认证的 Provider 类型。
实际中,每个 AuthenticationProvider 都会去执行一个特定类型的身份验证。例如,一个AuthenticationProvider 可能能够验证用户名/密码,而另一个 AuthenticationProvider 可能能够验证 SAML 断言。Spring Security 同时支持多种身份验证类型,并且只公开一个通用的 AuthenticationManager Bean。//对应各种功能的过滤器
ProviderManager 还允许配置一个父类 AuthenticationManager(可选),它在没有AuthenticationProvider 可以执行身份验证的情况下被使用。父类可以是任何类型的 AuthenticationManager,通常也是一个 ProviderManager 实例。
多个 ProviderManager 实例可以共享同一个父 AuthenticationManager。该方式在存在多个 SecurityFilterChain 的场景中比较常见,这些安全过滤器链有一些共同的身份验证(共享的父AuthenticationManager),但也有不同的身份验证机制(不同的 ProviderManager 实例)。
默认情况下,ProviderManager 会尝试从成功的身份验证请求返回的 Authentication 对象中清除敏感的凭据信息,防止信息(如密码)在 HttpSession 中保留的时间超过所需的时间。// Authentication 认证成功后,ProviderManager 会清除其中的认证凭据
// 因为ProviderManager会清除Authentication认证凭据,所以缓存Authentication信息时应该注意此问题。
解决缓存问题的两种方案:创建 Authentication 对象的副本或者禁用 ProviderManager 上的 eraseCredentialsAfterAuthentication 属性。
【ProviderManager.authenticate 源码分析】:
//执行认证的AuthenticationProvider列表
private List<AuthenticationProvider> providers; //认证流程
public Authentication authenticate(Authentication authentication) throws AuthenticationException {Class<? extends Authentication> toTest = authentication.getClass();AuthenticationException lastException = null;AuthenticationException parentException = null;Authentication result = null;Authentication parentResult = null;int currentPosition = 0;int size = this.providers.size();//1-获取Provider列表迭代器Iterator var9 = this.getProviders().iterator(); //2-开始循环遍历Provider列表while(var9.hasNext()) { AuthenticationProvider provider = (AuthenticationProvider)var9.next();if (provider.supports(toTest)) {//省略...try {//3-使用其中一个provider进行身份验证result = provider.authenticate(authentication);if (result != null) {this.copyDetails(authentication, result);break;}} catch (InternalAuthenticationServiceException | AccountStatusException var14) {this.prepareException(var14, authentication);throw var14;} catch (AuthenticationException var15) {lastException = var15;}}}//省略...(这里省略了付实例的认证,也很简单,可查看源码)//4-如果认证成功,在这里擦除密码/认证凭据等信息if (result != null) { if (this.eraseCredentialsAfterAuthentication && result instanceof CredentialsContainer) {((CredentialsContainer)result).eraseCredentials(); //擦除认证凭据}if (parentResult == null) {this.eventPublisher.publishAuthenticationSuccess(result);}return result;} else {//5-抛出providerNotFound异常if (lastException == null) {lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound", new Object[]{toTest.getName()}, "No AuthenticationProvider found for {0}"));}if (parentException == null) {this.prepareException((AuthenticationException)lastException, authentication);}throw lastException;}}
7、AuthenticationProvider 特定类型的身份验证接口
用于处理特定身份验证的统一接口。
通常可以将多个 AuthenticationProvider 实例注入到 ProviderManager 中。每个AuthenticationProvider 执行特定类型的身份验证。例如,DaoAuthenticationProvider 支持基于用户名/密码的身份验证,而 JwtAuthenticationProvider 支持验证 JWT 令牌。
public interface AuthenticationProvider {//执行身份验证Authentication authenticate(Authentication var1) throws AuthenticationException;//如果此AuthenticationProvider支持指定的Authentication对象,则返回true。boolean supports(Class<?> var1);
}
8、AuthenticationEntryPoint 身份验证方案接口
AuthenticationEntryPoint 作用:由 ExceptionTranslationFilter 用于启动一个身份验证方案。
public interface AuthenticationEntryPoint {//启动认证方案void commence(HttpServletRequest var1, HttpServletResponse var2, AuthenticationException var3) throws IOException, ServletException;
}
ExceptionTranslationFilter 将填充 AbstractAuthenticationProcessingFilter 的 HttpSession 属性。在调用此方法之前,使用所请求的目标URL。
实现根据需要修改 ServletResponse 上的报文头,以启动身份验证过程。AuthenticationEntryPoint 的实现可能会执行重定向到登录页面、使用 WWW-Authenticate 头响应或采取其他操作。
9、AbstractAuthenticationProcessingFilter 用户凭据验证过滤器
AbstractAuthenticationProcessingFilter 用作验证用户凭据的基本过滤器。在对凭证进行身份验证之前,Spring Security 通常会使用 AuthenticationEntryPoint 来请求凭证。
【AbstractAuthenticationProcessingFilter.doFilter 源码】//总流程
//身份认证过滤器的处理流程private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {if (!this.requiresAuthentication(request, response)) {chain.doFilter(request, response);} else {try {//1- 尝试进行身份验证Authentication authenticationResult = this.attemptAuthentication(request, response);if (authenticationResult == null) {return;}//2-如果验证成功,创建新会话,更新sessionIdthis.sessionStrategy.onAuthentication(authenticationResult, request, response);if (this.continueChainBeforeSuccessfulAuthentication) {chain.doFilter(request, response);}//3-调用认证成功后处理流程this.successfulAuthentication(request, response, chain, authenticationResult);} catch (InternalAuthenticationServiceException var5) {this.logger.error("An internal error occurred while trying to authenticate the user.", var5);//4-调用认证失败后处理流程this.unsuccessfulAuthentication(request, response, var5);} catch (AuthenticationException var6) {//4-调用认证失败后处理流程this.unsuccessfulAuthentication(request, response, var6);}}}
接下来,AbstractAuthenticationProcessingFilter 可以对提交给它的任何身份验证请求进行身份验证。
//过滤器中尝试进行身份验证的抽象方法public abstract Authentication attemptAuthentication(HttpServletRequest var1, HttpServletResponse var2) throws AuthenticationException, IOException, ServletException;//一个具体实现类:UsernamePasswordAuthenticationFilter的实现逻辑public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (this.postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());} else {String username = this.obtainUsername(request);username = username != null ? username : "";username = username.trim();String password = this.obtainPassword(request);password = password != null ? password : "";//使用用户名和密码创建一个Authentication对象UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);this.setDetails(request, authRequest);//调用特定的认证管理器进行认证,通常为(ProviderManager)return this.getAuthenticationManager().authenticate(authRequest);}}
AbstractAuthenticationProcessingFilter 进行认证的流程图示:
当用户提交凭据时,AbstractAuthenticationProcessingFilter 从 HttpServletRequest 创建一个要进行身份验证的 Authentication 对象。创建的身份验证类型取决于AbstractAuthenticationProcessingFilter 的子类。例如,UsernamePasswordAuthenticationFilter 从 HttpServletRequest 中提交的用户名和密码中创建 UsernamePasswordAuthenticationToken。//看上边的源码展示
接下来,将 Authentication 对象 传递到 AuthenticationManager 中进行身份验证。
如果身份验证失败,则执行 Failure 流程://失败流程,有许多的拓展点
(1)调用 SecurityContextHolder.clearContext 方法清除 Security 上下文。//ThreadLocal.remove
(2)调用 RememberMeServices.loginFail 方法。有两个实现类 NullRememberMe 和 RememberMe。 //RememberMe会失效Cookie
(3)调用 AuthenticationFailureHandler.onAuthenticationFailure 方法。//抛出错误信息或者重定向
【AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication 源码】
//认证失败处理流程protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {//1-清除SecurityContextHolderSecurityContextHolder.clearContext();this.logger.trace("Failed to process authentication request", failed);this.logger.trace("Cleared SecurityContextHolder");this.logger.trace("Handling authentication failure");//2-调用RememberMeServices.loginFailthis.rememberMeServices.loginFail(request, response);//3-调用AuthenticationFailureHandlerthis.failureHandler.onAuthenticationFailure(request, response, failed);}
如果身份验证成功,则执行 Success 流程:
(1)SessionAuthenticationStrategy.onAuthentication 会收到新的登录通知。
(2)在 SecurityContextHolder 中设置通过认证的用户信息,方便后续取用。
(3)调用 RememberMeServices.loginSuccess 方法。//通过此方法可自定义成功后的处理方式。
(4)调用 ApplicationEventPublisher.publishEvent 方法发布一个InteractiveAuthenticationSuccessEvent 事件。//用户可通过监听此事件来做进一步操作
(5)调用 AuthenticationSuccessHandler.onAuthenticationSuccess 方法。//处理url重定向等
【AbstractAuthenticationProcessingFilter.successfulAuthentication 源码】
//认证成功处理流程protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {//1-在 SecurityContextHolder 中设置通过认证的用户信息,方便后续取用SecurityContextHolder.getContext().setAuthentication(authResult);if (this.logger.isDebugEnabled()) {this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));}//2-调用 RememberMeServices.loginSuccess 方法this.rememberMeServices.loginSuccess(request, response, authResult);if (this.eventPublisher != null) {//3-发布认证成功事件this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));}//4-调用AuthenticationSuccessHandler.onAuthenticationSuccess方法this.successHandler.onAuthenticationSuccess(request, response, authResult);}
最后,熟知用户的认证流程,对熟练使用 Spring Security 非常重要。需要多学习,多总结。
至此,全文到此结束。
相关文章:

Spring Security 身份验证的基本类/架构
目录 1、SecurityContextHolder 核心类 2、SecurityContext 接口 3、Authentication 用户认证信息接口 4、GrantedAuthority 拥有权限接口 5、AuthenticationManager 身份认证管理器接口 6、ProviderManager 身份认证管理器的实现 7、AuthenticationProvider 特定类型的…...
市值超300亿美金,SaaS独角兽Veeva如何讲好中国故事?
“全球前50的药企,有47家正在使用Veeva。” 提到Veeva Systems(以下简称“Veeva”),可能很多人并不熟悉。但是生命科学业内人士都知道,Veeva是全球头部的行业SaaS服务商。以“为生命科学行业构建行业云”为使命&#x…...

编译内联导致内存泄漏的问题定位修复
作者:0x264 问题 线上长时间存在一个跟异步 inflate 相关的量级较大的内存泄漏,如下所示: 第一次分析 从内存泄漏粗略看有几个信息: 被泄漏的Activity有很多,所以可能跟某个具体业务的关系不大引用链特别短…...

基于WebSocket实现的后台服务
基于WebSocket实现的后台服务,用于接收客户端的心跳消息,并根据心跳消息来维护客户端连接。 具体实现中,服务启动后会创建一个HttpListener对象,用于监听客户端的WebSocket连接请求。当客户端连接成功后,服务会为每个…...

Go语言中的结构体详解
关于 Golang 结构体 Golang 中没有“类”的概念,Golang 中的结构体和其他语言中的类有点相似。和其他面向对 象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性。 Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们…...

pytest自动化测试指定执行测试用例
1、在控制台执行 打开cmd,进入项目目录 指定执行某个模块 pytest testcases\Logistics\Platform\CarSource\test_CarSourceList.py 指定执行某个目录及其子目录的所有测试文件 pytest testcases\Logistics\Platform\CarSource 指定执行某个模块的某个类的某个测试用例 pyte…...

英伟达 H100 vs. 苹果M2,大模型训练,哪款性价比更高?
M1芯片 | Uitra | AMD | A100 M2芯片 | ARM | A800 | H100 关键词:M2芯片;Ultra;M1芯片;UltraFusion;ULTRAMAN;RTX4090、A800;A100;H100;LLAMA、LM、AIGC、CHATGLM、LLVM、LLM、LLM…...

var、let和const的区别
先简单了解一下 var声明的变量会挂载在window上,而let和const声明的变量不会: var a 100; console.log(a,window.a); // 100 100let b 10; console.log(b,window.b); // 10 undefinedconst c 1; console.log(c,window.c); // 1 undefined v…...

(css)AI智能问答页面布局
(css)AI智能问答页面布局 效果: html <!-- AI框 --><div class"chat-top"><div class"chat-main" ref"chatList"><div v-if"!chatList.length" class"no-message"><span>欢迎使…...

【Pytorch学习】pytorch中的isinstance() 函数
描述 isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。 isinstance() 与 type() 区别: type() 不会认为子类是一种父类类型,不考虑继承关系。 isinstance() 会认为子类是一种父类类型,考虑继承关系。 如果要判…...

(树) 剑指 Offer 07. 重建二叉树 ——【Leetcode每日一题】
❓剑指 Offer 07. 重建二叉树 难度:中等 输入某二叉树的 前序遍历 和 中序遍历 的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,20,7] …...

Gitlab 合并分支与请求合并
合并分支 方式一:图形界面 使用 GitGUI,右键菜单“GitExt Browse” - 菜单“命令” - 合并分支 方式二:命令行 在项目根目录下打开控制台,注意是本地 dev 与远程 master 的合并 // 1.查看本地分支,确认当前分支是否…...

【Matter】基于Ubuntu 22.04 编译chip-tool工具
前言 编译过程有点曲折,做下记录,过程中,有参考别人写的博客,也看github 官方介绍,终于跑通了~ 环境说明: 首先需要稳定的梯子,可以访问“外网”ubuntu 环境,最终成功实验在Ubunt…...

将 MongoDB 的 List<Document> 转换为对象列表
当我们使用 MongoDB 存储数据时,经常会涉及到将 MongoDB 的文档对象转换为对象列表的需求。在 Java 中,我们可以使用 MongoDB 的 Java 驱动程序和自定义类来实现这一转换过程。 本篇博客将介绍如何将 MongoDB 中的 List<Document> 转换为对象列表。…...

【Linux下6818开发板(ARM)】SecureCRT串口和交叉编译工具(巨细版!)
(꒪ꇴ꒪ ),hello我是祐言博客主页:C语言基础,Linux基础,软件配置领域博主🌍快上🚘,一起学习!送给读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!作者水平很有限,如果发现错误&#x…...
应届生如何快速找Java开发工程师,先学会这17个基础问题
一、Java 基础 JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的…...

数学建模学习(5):数学建模各类题型及解题方案
一、数学建模常见的题型 总体来说,数学建模赛题类型主要分为:评价类、预测类和优化类三种,其中优化类是最常见的赛题类 型,几乎每年的地区赛或国赛美赛等均有出题,必须要掌握并且熟悉。 二、评价类赛题 综合评价是数学…...

【学习笔记】视频检测方法调研
目录 1 引言2 方法2.1 视频目标跟踪2.1.1 生成式模型方法2.1.2 判别式模型方法2.1.2.1 基于相关滤波跟踪2.1.2.2 基于深度学习跟踪 2.2 视频异常检测2.2.1 基于重构方法2.2.2 基于预测方法2.2.3 基于分类方法2.2.4 基于回归方法 2.3 深度伪造人脸视频检测2.3.1 基于RNN时空融合…...

idea terminal npm指令无效
文章目录 一、修改setting二、修改启动方式 一、修改setting 菜单栏:File->Settings 二、修改启动方式 快捷方式->右键属性->兼容性->勾选管理员身份运行...

低代码开发平台源码
什么是低代码开发平台? 低代码来源于英文“Low Code,它意指一种快速开发的方式,使用最少的代码、以最快的速度来交付应用程序。通俗的来说,就是所需代码数量低,开发人员门槛低,操作难度低。一般采用简单的图…...

【UE5 多人联机教程】04-加入游戏
效果 步骤 1. 新建一个控件蓝图,父类为“USC_Button_Standard” 控件蓝图命名为“UMG_Item_Room”,用于表示每一个搜索到的房间的界面 打开“UMG_Item_Room”,在图表中新建一个变量,命名为“Session” 变量类型为“蓝图会话结果…...

自然语言处理从入门到应用——LangChain:模型(Models)-[大型语言模型(LLMs):缓存LLM的调用结果]
分类目录:《自然语言处理从入门到应用》总目录 from langchain.llms import OpenAI在内存中缓存 import langchain from langchain.cache import InMemoryCachelangchain.llm_cache InMemoryCache()# To make the caching really obvious, lets use a slower mode…...

Python 算法基础篇之图的遍历算法:深度优先搜索和广度优先搜索
Python 算法基础篇之图的遍历算法:深度优先搜索和广度优先搜索 引言 1. 图的遍历概述2. 深度优先搜索( DFS )2.1 DFS 的实现2.2 DFS 的应用场景 3. 广度优先搜索( BFS )3.1 BFS 的实现3.2 BFS 的应用场景 4. 示例与实例…...

文本缩略 文本超出显示省略号 控制超出省略的行数
文本缩略 .abb{//超出一行省略overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }超出2行省略 .abb2{display: -webkit-box !important;-webkit-box-orient: vertical;//超出2行省略-webkit-line-clamp:2;overflow: hidden; }控制超出省略的行数 .txt-over{/*控…...

云原生架构
1. 何为云原生? 很多IT业内小伙伴会经常听到这个名词,那么什么是云原生呢?云原生是在云计算环境中构建、部署和管理现代应用程序的软件方法。 当今时代,众多企业希望构建高度可扩展、灵活且有弹性的应用程序,以便能够快…...

Java 生成随机数据
文章目录 1. Java-faker依赖demo 2. common-random依赖demo 1. Java-faker 依赖 <dependency><groupId>com.github.javafaker</groupId><artifactId>javafaker</artifactId><version>1.0.2</version> </dependency>https://…...

基于OpenCV的红绿灯识别
基于OpenCV的红绿灯识别 技术背景 为了实现轻舟航天机器人实现红绿灯的识别,决定采用传统算法OpenCV视觉技术。 技术介绍 航天机器人的红绿灯识别主要基于传统计算机视觉技术,利用OpenCV算法对视频流进行处理,以获取红绿灯的状态信息。具…...

JavaScript快速入门:ComPDFKit PDF SDK 快速构建 Web端 PDF阅读器
JavaScript快速入门:ComPDFKit PDF SDK 快速构建 Web端 PDF阅读器 在当今丰富的网络环境中,处理 PDF 文档已成为企业和开发人员的必需品。ComPDFKit 是一款支持 Web 平台并且功能强大的 PDF SDK,开发人员可以利用它创建 PDF 查看器和编辑器&…...

Flutter 网络请求
在Flutter 中常见的网络请求方式有三种:HttpClient、http库、dio库; 本文简单介绍 使用dio库使用。 选择dio库的原因: dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载…...

吃透《西瓜书》第三章 线性模型:多元线性回归
🍉 吃瓜系列 教材:《机器学习》 周志华著 🕒时间:2023/7/26 目录 一、多元线性回归 1 向量化 1.1.1 向量化 1.1.2 使用最小二乘法构建损失函数 1.1.3 去除求和符号,改成向量点乘的形式 1.1.4 数学原理 2 求解…...